<commit_before>
/**
 * NNMatrix.cpp
 * ۼ: ̼
 * ۼ: 2013. 11. 27
 *   : ̼
 * : 2013. 12. 04
 */

#include "NNMatrix.h"

NNMatrix::NNMatrix()
{
	Identity();
}
NNMatrix::NNMatrix( float _11, float _12, float _21, float _22, float _31, float _32 )
{
	this->_11 = _11;
	this->_12 = _12;
	this->_21 = _21;
	this->_22 = _22;
	this->_31 = _31;
	this->_32 = _32;
}
NNMatrix::~NNMatrix()
{
}

void NNMatrix::Identity()
{
	_11 = 1.f; _12 = 0.f;
	_21 = 0.f; _22 = 1.f;
	_31 = 0.f; _32 = 0.f;
}
NNMatrix NNMatrix::Scale( NNPoint size )
{
	NNMatrix instance;
	instance._11 = size.GetX(); instance._12 = 0.0f;
	instance._21 = 0.0f; instance._22 = size.GetY();
	instance._31 = 0.0f; instance._32 = 0.0f;
	return instance;
}
NNMatrix NNMatrix::Scale( float x, float y )
{
	return Scale( NNPoint(x, y) );
}
NNMatrix NNMatrix::Translate( NNPoint size )
{
	NNMatrix instance;
	instance._11 = 1.0f; instance._12 = 0.0f;
	instance._21 = 0.0f; instance._22 = 1.0f;
	instance._31 = size.GetX(); instance._32 = size.GetY();
	return instance;
}
NNMatrix NNMatrix::Translate( float x, float y )
{
	return Translate( NNPoint(x,y) );
}
NNMatrix NNMatrix::Rotation( float angle )
{
	NNMatrix instance;
	instance._11 = cos(angle); instance._12 = sin(angle);
	instance._21 = -sin(angle); instance._22 = cos(angle);
	instance._31 = 0.0f; instance._32 = 0.0f;
	return instance;
}

bool NNMatrix::IsIdentity() const
{
	return _11 == 1.f && _12 == 0.f
			&& _21 == 0.f && _22 == 1.f
			&& _31 == 0.f && _32 == 0.f;
}

float NNMatrix::Determinant() const
{
	return (_11 * _22) - (_12 * _21);
}

NNMatrix& NNMatrix::operator= ( const NNMatrix& matrix )
{
	this->_11 = matrix._11; this->_12 = matrix._12;
	this->_21 = matrix._21; this->_22 = matrix._22;
	this->_31 = matrix._31; this->_32 = matrix._32;
	return *this;
}
NNMatrix NNMatrix::operator+( const NNMatrix& matrix ) const
{
	return NNMatrix(
		this->_11+matrix._11, this->_12+matrix._12,
		this->_21+matrix._21, this->_22+matrix._22,
		this->_31+matrix._31, this->_32+matrix._32 );
}
NNMatrix NNMatrix::operator-( const NNMatrix& matrix ) const
{
	return NNMatrix(
		this->_11-matrix._11, this->_12-matrix._12,
		this->_21-matrix._21, this->_22-matrix._22,
		this->_31-matrix._31, this->_32-matrix._32 );
}
NNMatrix NNMatrix::operator-() const
{
	return NNMatrix(
		-this->_11, -this->_12,
		-this->_21, -this->_22,
		-this->_31, -this->_32 );
}
NNMatrix NNMatrix::operator*( float n ) const
{
	return NNMatrix(
		-this->_11*n, -this->_12*n,
		-this->_21*n, -this->_22*n,
		-this->_31*n, -this->_32*n );
}
NNMatrix NNMatrix::operator/( float n ) const
{
	return NNMatrix(
		-this->_11/n, -this->_12/n,
		-this->_21/n, -this->_22/n,
		-this->_31/n, -this->_32/n );
}
NNMatrix NNMatrix::operator*( const NNMatrix& matrix ) const
{
	return NNMatrix(
		this->_11*matrix._11 + this->_12*matrix._21,
		this->_11*matrix._12 + this->_12*matrix._22,
		this->_21*matrix._11 + this->_22*matrix._21,
		this->_21*matrix._12 + this->_22*matrix._22,
		this->_31*matrix._11 + this->_32*matrix._21 + matrix._31,
		this->_31*matrix._12 + this->_32*matrix._22 + matrix._32 );
}<commit_msg># fix nnmatrix.cpp<commit_after>
/**
 * NNMatrix.cpp
 * ۼ: ̼
 * ۼ: 2013. 11. 27
 *   : ȯ
 *   : Rotate  Degree . ׸
 * : 2013. 12. 10
 */

#include "NNMatrix.h"

NNMatrix::NNMatrix()
{
	Identity();
}
NNMatrix::NNMatrix( float _11, float _12, float _21, float _22, float _31, float _32 )
{
	this->_11 = _11;
	this->_12 = _12;
	this->_21 = _21;
	this->_22 = _22;
	this->_31 = _31;
	this->_32 = _32;
}
NNMatrix::~NNMatrix()
{
}

void NNMatrix::Identity()
{
	_11 = 1.f; _12 = 0.f;
	_21 = 0.f; _22 = 1.f;
	_31 = 0.f; _32 = 0.f;
}
NNMatrix NNMatrix::Scale( NNPoint size )
{
	NNMatrix instance;
	instance._11 = size.GetX(); instance._12 = 0.0f;
	instance._21 = 0.0f; instance._22 = size.GetY();
	instance._31 = 0.0f; instance._32 = 0.0f;
	return instance;
}
NNMatrix NNMatrix::Scale( float x, float y )
{
	return Scale( NNPoint(x, y) );
}
NNMatrix NNMatrix::Translate( NNPoint size )
{
	NNMatrix instance;
	instance._11 = 1.0f; instance._12 = 0.0f;
	instance._21 = 0.0f; instance._22 = 1.0f;
	instance._31 = size.GetX(); instance._32 = size.GetY();
	return instance;
}
NNMatrix NNMatrix::Translate( float x, float y )
{
	return Translate( NNPoint(x,y) );
}
NNMatrix NNMatrix::Rotation( float angle )
{
	NNMatrix instance;
	instance._11 = cos(angle); instance._12 = sin(angle);
	instance._21 = -sin(angle); instance._22 = cos(angle);
	instance._31 = 0.0f; instance._32 = 0.0f;
	return instance;
}

bool NNMatrix::IsIdentity() const
{
	return _11 == 1.f && _12 == 0.f
			&& _21 == 0.f && _22 == 1.f
			&& _31 == 0.f && _32 == 0.f;
}

float NNMatrix::Determinant() const
{
	return (_11 * _22) - (_12 * _21);
}

NNMatrix& NNMatrix::operator= ( const NNMatrix& matrix )
{
	this->_11 = matrix._11; this->_12 = matrix._12;
	this->_21 = matrix._21; this->_22 = matrix._22;
	this->_31 = matrix._31; this->_32 = matrix._32;
	return *this;
}
NNMatrix NNMatrix::operator+( const NNMatrix& matrix ) const
{
	return NNMatrix(
		this->_11+matrix._11, this->_12+matrix._12,
		this->_21+matrix._21, this->_22+matrix._22,
		this->_31+matrix._31, this->_32+matrix._32 );
}
NNMatrix NNMatrix::operator-( const NNMatrix& matrix ) const
{
	return NNMatrix(
		this->_11-matrix._11, this->_12-matrix._12,
		this->_21-matrix._21, this->_22-matrix._22,
		this->_31-matrix._31, this->_32-matrix._32 );
}
NNMatrix NNMatrix::operator-() const
{
	return NNMatrix(
		-this->_11, -this->_12,
		-this->_21, -this->_22,
		-this->_31, -this->_32 );
}
NNMatrix NNMatrix::operator*( float n ) const
{
	return NNMatrix(
		-this->_11*n, -this->_12*n,
		-this->_21*n, -this->_22*n,
		-this->_31*n, -this->_32*n );
}
NNMatrix NNMatrix::operator/( float n ) const
{
	return NNMatrix(
		-this->_11/n, -this->_12/n,
		-this->_21/n, -this->_22/n,
		-this->_31/n, -this->_32/n );
}
NNMatrix NNMatrix::operator*( const NNMatrix& matrix ) const
{
	return NNMatrix(
		this->_11*matrix._11 + this->_12*matrix._21,
		this->_11*matrix._12 + this->_12*matrix._22,
		this->_21*matrix._11 + this->_22*matrix._21,
		this->_21*matrix._12 + this->_22*matrix._22,
		this->_31*matrix._11 + this->_32*matrix._21 + matrix._31,
		this->_31*matrix._12 + this->_32*matrix._22 + matrix._32 );
}<|endoftext|>


<commit_before>/** @copyright
 * Copyright (c) 2017, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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.
 *
 * @file NonAthoritativeEventProducer.hxx
 *
 * Defines implementations of Event Producers that are uathoratative, meaning
 * that they do not represent the actual state of an event, but can still
 * query that state (presumably from a consumer) and produce a new state.
 *
 * @author Stuart Baker
 * @date 17 June 2017
 */

#ifndef _OPENLCB_NONAUTHORITATIVEEVENTPRODUCER_HXX_
#define _OPENLCB_NONAUTHORITATIVEEVENTPRODUCER_HXX_

#include "openlcb/EventHandlerTemplates.hxx"

namespace openlcb
{

/// Event producer for range of bits (event pairs) that is non-autoritative.
class BitRangeNonAuthoritativeEventP : public SimpleEventHandler
{
public:
    /// Constructor.  Creates a new bit range producer.
    ///
    /// @param node the node that the producer will be bound to
    /// @param event_base the starting event ID for the event range
    /// @param size The total event range size in "pairs" of events.  Each
    ///             pair of sequential events represents a single "bit" with
    ///             a binary state.
    /// @param state_callback Callback method for delivering the results of a
    ///                       consumer identified.  The first unsigned parameter
    ///                       represents the bit offset for the range and
    ///                       the second bool parameter indicates the state as
    ///                       true for valid and false for invalid
    BitRangeNonAuthoritativeEventP(Node *node, uint64_t event_base,
                  uint32_t size,
                  std::function<void(unsigned, bool)> state_callback = nullptr)
        : node_(node)
        , eventBase_(event_base)
        , eventBaseOff_(0)
        , size_(size)
        , stateCallback_(state_callback)
    {
        unsigned mask = EventRegistry::align_mask(&event_base, size * 2);
        EventRegistry::instance()->register_handler(
            EventRegistryEntry(this, event_base), mask);
    }

    /// Constructor.  Creates a new bit range producer.
    ///
    /// @param node the node that the producer will be bound to
    /// @param event_base_on the starting event ID for the "on" event range
    /// @param event_base_off the starting event ID for the "off" event range
    /// @param size The total event range size in "pairs" of events.  Each
    ///             pair of sequential events represents a single "bit" with
    ///             a binary state.
    /// @param state_callback Callback method for delivering the results of a
    ///                       consumer identified.  The first unsigned parameter
    ///                       represents the bit offset for the range and
    ///                       the second bool parameter indicates the state as
    ///                       true for valid and false for invalid
    BitRangeNonAuthoritativeEventP(Node *node, uint64_t event_base_on,
                  uint64_t event_base_off, uint32_t size,
                  std::function<void(unsigned, bool)> state_callback = nullptr)
        : node_(node)
        , eventBaseOn_(event_base_on)
        , eventBaseOff_(event_base_off)
        , size_(size)
        , stateCallback_(state_callback)
    {
        unsigned mask;

        mask = EventRegistry::align_mask(&event_base_on, size);
        EventRegistry::instance()->register_handler(
            EventRegistryEntry(this, event_base_on), mask);

        mask = EventRegistry::align_mask(&event_base_off, size);
        EventRegistry::instance()->register_handler(
            EventRegistryEntry(this, event_base_off), mask);
    }

    /// Destructor.
    ~BitRangeNonAuthoritativeEventP()
    {
        EventRegistry::instance()->unregister_handler(this);
    }

    /// Queries consumer and acquires the current state of the bit.
    ///
    /// @param bit bit pair offset from the base event ID of the range,
    ///            (0 <= bit < size)
    /// @param writer object that will assist in the write transaction
    /// @param done notifible to wakup when finished
    void send_query_consumer(unsigned bit, WriteHelper *writer,
                             BarrierNotifiable *done);

    /// Requests the event associated with the current value of the bit to be
    /// produced (unconditionally).
    ///
    /// @param bit is the offset of the bit to set (0 <= bit < size)
    /// @param new_value is the new value of the bit
    /// @param writer is the output flow to be used
    /// @param done notifible to wakup when finished
    void set(unsigned bit, bool new_value, WriteHelper *writer,
             BarrierNotifiable *done);

    /// Handle an incoming event.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished
    void handle_event_report(const EventRegistryEntry &entry,
                             EventReport *event,
                             BarrierNotifiable *done) override;

    /// Handle an incoming consumer identified message.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished
    void handle_consumer_identified(const EventRegistryEntry &entry,
                                    EventReport *event,
                                    BarrierNotifiable *done) override;

    /// Handle an incoming identify producer message.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished
    void handle_identify_global(const EventRegistryEntry &entry,
                                EventReport *event,
                                BarrierNotifiable *done) override;

    /// Handle an incoming identify producer message.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished
    void handle_identify_producer(const EventRegistryEntry &entry,
                                  EventReport *event,
                                  BarrierNotifiable *done) override;

private:
    Node *node_; ///< Node ID that this producer is attached to
    union
    {
        uint64_t eventBase_; ///< base event ID of the full range
        uint64_t eventBaseOn_; ///< base event ID for "on" range
    };
    uint64_t eventBaseOff_; ///< base event ID for "off" range
    unsigned size_; ///< number of bits stored

    /// Callback method that will be invoked when a consumer identified
    /// message is received with a known state.
    std::function<void(unsigned, bool)> stateCallback_;

    DISALLOW_COPY_AND_ASSIGN(BitRangeNonAuthoritativeEventP);
};

} // namespace openlcb

#endif // _OPENLCB_AUTHORITATIVEEVENTPRODUCER_HXX_

<commit_msg>Update documenting comments.<commit_after>/** @copyright
 * Copyright (c) 2017, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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.
 *
 * @file NonAthoritativeEventProducer.hxx
 *
 * Defines implementations of Event Producers that are uathoratative, meaning
 * that they do not represent the actual state of an event, but can still
 * query that state (presumably from a consumer) and produce a new state.
 *
 * @author Stuart Baker
 * @date 17 June 2017
 */

#ifndef _OPENLCB_NONAUTHORITATIVEEVENTPRODUCER_HXX_
#define _OPENLCB_NONAUTHORITATIVEEVENTPRODUCER_HXX_

#include "openlcb/EventHandlerTemplates.hxx"

namespace openlcb
{

/// Event producer for range of bits (event pairs) that is non-autoritative.
class BitRangeNonAuthoritativeEventP : public SimpleEventHandler
{
public:
    /// Constructor.  Creates a new bit range producer.
    ///
    /// @param node the node that the producer will be bound to
    /// @param event_base the starting event ID for the event range
    /// @param size The total event range size in "pairs" of events.  Each
    ///             pair of sequential events represents a single "bit" with
    ///             a binary state.
    /// @param state_callback Callback method for delivering the results of a
    ///                       consumer identified.  The first unsigned parameter
    ///                       represents the bit offset for the range and
    ///                       the second bool parameter indicates the state as
    ///                       true for valid and false for invalid
    BitRangeNonAuthoritativeEventP(Node *node, uint64_t event_base,
                  uint32_t size,
                  std::function<void(unsigned, bool)> state_callback = nullptr)
        : node_(node)
        , eventBase_(event_base)
        , eventBaseOff_(0)
        , size_(size)
        , stateCallback_(state_callback)
    {
        unsigned mask = EventRegistry::align_mask(&event_base, size * 2);
        EventRegistry::instance()->register_handler(
            EventRegistryEntry(this, event_base), mask);
    }

    /// Constructor.  Creates a new bit range producer.
    ///
    /// @param node the node that the producer will be bound to
    /// @param event_base_on the starting event ID for the "on" event range
    /// @param event_base_off the starting event ID for the "off" event range
    /// @param size The total event range size in "pairs" of events.  Each
    ///             pair of sequential events represents a single "bit" with
    ///             a binary state.
    /// @param state_callback Callback method for delivering the results of a
    ///                       consumer identified or event report.  The first
    ///                       unsigned parameter represents the bit offset for
    ///                       the range and the second bool parameter indicates
    ///                       the state as true for valid and false for invalid.
    BitRangeNonAuthoritativeEventP(Node *node, uint64_t event_base_on,
                  uint64_t event_base_off, uint32_t size,
                  std::function<void(unsigned, bool)> state_callback = nullptr)
        : node_(node)
        , eventBaseOn_(event_base_on)
        , eventBaseOff_(event_base_off)
        , size_(size)
        , stateCallback_(state_callback)
    {
        unsigned mask;

        mask = EventRegistry::align_mask(&event_base_on, size);
        EventRegistry::instance()->register_handler(
            EventRegistryEntry(this, event_base_on), mask);

        mask = EventRegistry::align_mask(&event_base_off, size);
        EventRegistry::instance()->register_handler(
            EventRegistryEntry(this, event_base_off), mask);
    }

    /// Destructor.
    ~BitRangeNonAuthoritativeEventP()
    {
        EventRegistry::instance()->unregister_handler(this);
    }

    /// Queries consumer and acquires the current state of the bit.
    ///
    /// @param bit bit pair offset from the base event ID of the range,
    ///            (0 <= bit < size)
    /// @param writer object that will assist in the write transaction
    /// @param done notifible to wakup when finished
    void send_query_consumer(unsigned bit, WriteHelper *writer,
                             BarrierNotifiable *done);

    /// Requests the event associated with the current value of the bit to be
    /// produced (unconditionally).
    ///
    /// @param bit is the offset of the bit to set (0 <= bit < size)
    /// @param new_value is the new value of the bit
    /// @param writer is the output flow to be used
    /// @param done notifible to wakup when query is sent on the bus
    void set(unsigned bit, bool new_value, WriteHelper *writer,
             BarrierNotifiable *done);

    /// Handle an incoming event.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished with the report processing
    void handle_event_report(const EventRegistryEntry &entry,
                             EventReport *event,
                             BarrierNotifiable *done) override;

    /// Handle an incoming consumer identified message.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished with the report processing
    void handle_consumer_identified(const EventRegistryEntry &entry,
                                    EventReport *event,
                                    BarrierNotifiable *done) override;

    /// Handle an incoming identify global or addressed message.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished with the report processing
    void handle_identify_global(const EventRegistryEntry &entry,
                                EventReport *event,
                                BarrierNotifiable *done) override;

    /// Handle an incoming identify producer message.
    ///
    /// @param entry reference to this entry in the event registry
    /// @param event event metadata
    /// @param done notifible to wakup when finished with the report processing
    void handle_identify_producer(const EventRegistryEntry &entry,
                                  EventReport *event,
                                  BarrierNotifiable *done) override;

private:
    Node *node_; ///< Node ID that this producer is attached to
    union
    {
        uint64_t eventBase_; ///< base event ID of the full range
        uint64_t eventBaseOn_; ///< base event ID for "on" range
    };
    uint64_t eventBaseOff_; ///< base event ID for "off" range
    unsigned size_; ///< number of bits stored

    /// Callback method that will be invoked when a consumer identified
    /// message is received with a known state.
    std::function<void(unsigned, bool)> stateCallback_;

    DISALLOW_COPY_AND_ASSIGN(BitRangeNonAuthoritativeEventP);
};

} // namespace openlcb

#endif // _OPENLCB_AUTHORITATIVEEVENTPRODUCER_HXX_

<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2012, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * 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.
*     * Neither the name of Hobu, Inc. or Flaxen Consulting LLC nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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
* COPYRIGHT OWNER OR 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.
****************************************************************************/

#include <pdal/GlobalEnvironment.hpp>
#include <pdal/plang/PythonEnvironment.hpp>

namespace pdal
{

//
// static functions
//

static GlobalEnvironment* t = 0;
static boost::once_flag flag = BOOST_ONCE_INIT;

GlobalEnvironment& GlobalEnvironment::get()
{
    boost::call_once(init, flag);
    return *t;
}

void GlobalEnvironment::startup()
{
    get();
}

void GlobalEnvironment::shutdown()
{
    // Shutdown could be called multiple times?
    if (t != 0)
        delete t;
    t = 0;
}

void GlobalEnvironment::init()
{
    t = new GlobalEnvironment();
}

//
// regular member functions
//

GlobalEnvironment::GlobalEnvironment()
{
    // this should be the not-a-thread thread environment
    (void) createThreadEnvironment(boost::thread::id());

    return;
}

GlobalEnvironment::~GlobalEnvironment()
{
    while (m_threadMap.size())
    {
        thread_map::iterator iter = m_threadMap.begin();
        ThreadEnvironment* env = iter->second;
        delete env;
        m_threadMap.erase(iter);
    }

    return;
}

void GlobalEnvironment::createThreadEnvironment(boost::thread::id id)
{
    ThreadEnvironment* threadEnv = new ThreadEnvironment(id);

    m_threadMap.insert( std::make_pair(id, threadEnv ) );
}

ThreadEnvironment& GlobalEnvironment::getThreadEnvironment(boost::thread::id id)
{
    thread_map::iterator iter =  m_threadMap.find(id);
    if (iter == m_threadMap.end())
        throw pdal_error("bad thread id!");

    ThreadEnvironment* threadEnv = iter->second;

    return *threadEnv;
}

#ifdef PDAL_HAVE_PYTHON
plang::PythonEnvironment& GlobalEnvironment::getPythonEnvironment()
{
    return getThreadEnvironment().getPythonEnvironment();
}
#endif

boost::random::mt19937* GlobalEnvironment::getRNG()
{
    return getThreadEnvironment().getRNG();
}

} //namespaces
<commit_msg>protect against shutdown() being called multiple times<commit_after>/******************************************************************************
* Copyright (c) 2012, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * 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.
*     * Neither the name of Hobu, Inc. or Flaxen Consulting LLC nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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
* COPYRIGHT OWNER OR 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.
****************************************************************************/

#include <pdal/GlobalEnvironment.hpp>
#include <pdal/plang/PythonEnvironment.hpp>

namespace pdal
{

//
// static functions
//

static GlobalEnvironment* t = 0;
static boost::once_flag flag = BOOST_ONCE_INIT;

GlobalEnvironment& GlobalEnvironment::get()
{
    boost::call_once(init, flag);
    return *t;
}

void GlobalEnvironment::startup()
{
    get();
}

void GlobalEnvironment::shutdown()
{
    // Shutdown could be called multiple times?
    if (t != 0)
    {
        delete t;
        t = 0;
    }

}

void GlobalEnvironment::init()
{
    t = new GlobalEnvironment();
}

//
// regular member functions
//

GlobalEnvironment::GlobalEnvironment()
{
    // this should be the not-a-thread thread environment
    (void) createThreadEnvironment(boost::thread::id());

    return;
}

GlobalEnvironment::~GlobalEnvironment()
{
    while (m_threadMap.size())
    {
        thread_map::iterator iter = m_threadMap.begin();
        ThreadEnvironment* env = iter->second;
        delete env;
        m_threadMap.erase(iter);
    }

    return;
}

void GlobalEnvironment::createThreadEnvironment(boost::thread::id id)
{
    ThreadEnvironment* threadEnv = new ThreadEnvironment(id);

    // FIXME: What happens if the id is already in the map?
    m_threadMap.insert( std::make_pair(id, threadEnv ) );
}

ThreadEnvironment& GlobalEnvironment::getThreadEnvironment(boost::thread::id id)
{
    thread_map::iterator iter =  m_threadMap.find(id);
    if (iter == m_threadMap.end())
        throw pdal_error("bad thread id!");

    ThreadEnvironment* threadEnv = iter->second;

    return *threadEnv;
}

#ifdef PDAL_HAVE_PYTHON
plang::PythonEnvironment& GlobalEnvironment::getPythonEnvironment()
{
    return getThreadEnvironment().getPythonEnvironment();
}
#endif

boost::random::mt19937* GlobalEnvironment::getRNG()
{
    return getThreadEnvironment().getRNG();
}

} //namespaces
<|endoftext|>


<commit_before>#ifndef MJOLNIR_CORE_DCD_LOADER_HPP
#define MJOLNIR_CORE_DCD_LOADER_HPP
#include <mjolnir/core/LoaderBase.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/util/logger.hpp>
#include <iostream>
#include <fstream>
#include <iomanip>

namespace mjolnir
{

template<typename traitsT>
class DCDLoader final : public LoaderBase<traitsT>
{
  public:
    using base_type         = LoaderBase<traitsT>;
    using traits_type       = typename base_type::traits_type;
    using real_type         = typename base_type::real_type;
    using coordinate_type   = typename base_type::coordinate_type;
    using system_type       = typename base_type::system_type;

  public:

    explicit DCDLoader(const std::string& filename)
        : base_type(), filename_(filename),
          file_(filename_, std::ios::binary | std::ios::in),
          has_unitcell_(false)
    {
        if(!file_.good())
        {
            throw_exception<std::runtime_error>("[error] mjolnir::DCDLoader: "
                    "file open error: ", filename_);
        }
    }
    ~DCDLoader() override {}

    void initialize() override
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        // read header region and set `num_particles` and `num_frames`.

        // --------------------------------------------------------------------
        // the first block
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // signature

            this->number_of_frames_ = detail::read_bytes_as<std::int32_t>(file_);

            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // index_of_first
            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // save_interval
            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // total_step
            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // total_chains

            detail::skip_bytes(file_, 4 * sizeof(std::int32_t)); // 4x int flags

            std::ignore = detail::read_bytes_as<float>(file_);
            this->has_unitcell_ = (detail::read_bytes_as<std::int32_t>(file_) == 1);

            detail::skip_bytes(file_, 8 * sizeof(std::int32_t)); // 8x int flags

            std::ignore = detail::read_bytes_as<std::int32_t>(file_);

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);

            MJOLNIR_LOG_NOTICE("There are ", this->number_of_frames_, " frames in ",
                               this->filename_);

            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the first header block is inconsistent");
            }
        }

        // --------------------------------------------------------------------
        // the second block
        {
            const auto block_size_beg  = detail::read_bytes_as<std::int32_t>(file_);
            const auto number_of_lines = detail::read_bytes_as<std::int32_t>(file_);
            for(std::int32_t i=0; i<number_of_lines; ++i)
            {
                std::vector<char> comments(81, '\0');
                file_.read(comments.data(), 80);
                const std::string line(comments.begin(), comments.end());
                MJOLNIR_LOG_NOTICE("comment: ", line);
            }
            const auto block_size_end = detail::read_bytes_as<std::int32_t>(file_);

            if(block_size_beg != block_size_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the second header block is inconsistent");
            }
        }

        // --------------------------------------------------------------------
        // the third block
        {
            const auto block_size_beg  = detail::read_bytes_as<std::int32_t>(file_);
            this->number_of_particles_ = detail::read_bytes_as<std::int32_t>(file_);
            const auto block_size_end  = detail::read_bytes_as<std::int32_t>(file_);

            if(block_size_beg != block_size_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the second header block is inconsistent");
            }
        }
        MJOLNIR_LOG_NOTICE("There are ", this->number_of_particles_,
                           " particles in ", this->filename_);

        buffer_x_.resize(this->number_of_particles_);
        buffer_y_.resize(this->number_of_particles_);
        buffer_z_.resize(this->number_of_particles_);
        return;
    }

    std::size_t num_particles() const noexcept {return number_of_particles_;}
    std::size_t num_frames()    const noexcept {return number_of_frames_;}
    bool        is_eof()        const noexcept {return file_.eof();}

    bool load_next(system_type& sys) override
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        this->read_unitcell_if_needed(sys.boundary());
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            assert(buffer_x_.size() == this->number_of_particles_);
            file_.read(reinterpret_cast<char*>(this->buffer_x_.data()),
                       this->number_of_particles_ * sizeof(float));

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);
            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the coordinate block is inconsistent");
                return false;
            }
        }
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            assert(buffer_y_.size() == this->number_of_particles_);
            file_.read(reinterpret_cast<char*>(this->buffer_y_.data()),
                       this->number_of_particles_ * sizeof(float));

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);
            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the coordinate block is inconsistent");
                return false;
            }
        }
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            assert(buffer_z_.size() == this->number_of_particles_);
            file_.read(reinterpret_cast<char*>(this->buffer_z_.data()),
                       this->number_of_particles_ * sizeof(float));

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);
            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the coordinate block is inconsistent");
                return false;
            }
        }

        for(std::size_t i=0; i<sys.size(); ++i)
        {
            sys.position(i) = sys.adjust_position(math::make_coordinate<
                coordinate_type>(buffer_x_[i], buffer_y_[i], buffer_z_[i]));
        }
        return true;
    }

    std::string const& filename() const noexcept override {return filename_;}

  private:

    void read_unitcell_if_needed(
        UnlimitedBoundary<real_type, coordinate_type>&) noexcept
    {
        return; // No boundary exists. Do nothing.
    }
    void read_unitcell_if_needed(
        CuboidalPeriodicBoundary<real_type, coordinate_type>& bdry) noexcept
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        if(!this->has_unitcell_)
        {
            MJOLNIR_LOG_WARN("dcd file ", this->filename_, " lacks unit cell "
                             "information.");
            return ;
        }

        const auto block_size_beg = detail::read_bytes_as<std::int32_t>(file_);
        const auto A              = detail::read_bytes_as<double>(file_);
        const auto gamma          = detail::read_bytes_as<double>(file_);
        const auto B              = detail::read_bytes_as<double>(file_);
        const auto beta           = detail::read_bytes_as<double>(file_);
        const auto alpha          = detail::read_bytes_as<double>(file_);
        const auto C              = detail::read_bytes_as<double>(file_);
        const auto block_size_end = detail::read_bytes_as<std::int32_t>(file_);

        if(block_size_beg != block_size_end)
        {
            MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
            MJOLNIR_LOG_WARN("Size of the unitcell block is inconsistent");
        }

        constexpr double half_pi = math::constants<double>::half_pi();

        if((differs(alpha, 90.0) && differs(alpha, std::cos(half_pi))) ||
           (differs(beta,  90.0) && differs(beta,  std::cos(half_pi))) ||
           (differs(gamma, 90.0) && differs(gamma, std::cos(half_pi))))
        {
            MJOLNIR_LOG_WARN("The unit cell is not a rectangle");
            MJOLNIR_LOG_WARN("angle alpha = ", alpha);
            MJOLNIR_LOG_WARN("angle beta  = ", beta);
            MJOLNIR_LOG_WARN("angle gamma = ", gamma);
        }

        // set width; XXX it requires sys.adjust_position later because the
        // original lower bound is unknown (only the width is recorded).
        const auto& lw = bdry.lower_bound();
        bdry.set_upper_bound(math::make_coordinate<coordinate_type>(
                    math::X(lw) + A, math::Y(lw) + B, math::Z(lw) + C));
        return ;
    }

    static bool differs(const double lhs, const double rhs) noexcept
    {
        constexpr double rel_tol = math::rel_tolerance<double>();
        constexpr double abs_tol = math::abs_tolerance<double>();

        return abs_tol                     < std::abs(lhs - rhs) ||
               rel_tol * 0.5 * (lhs + rhs) < std::abs(lhs - rhs);
    }

  private:

    std::string        filename_;
    std::ifstream      file_;
    std::size_t        number_of_frames_;
    std::size_t        number_of_particles_;
    std::vector<float> buffer_x_;
    std::vector<float> buffer_y_;
    std::vector<float> buffer_z_;
    bool               has_unitcell_;
};

} // mjolnir

#ifdef MJOLNIR_SEPARATE_BUILD
#include <mjolnir/core/SimulatorTraits.hpp>
#include <mjolnir/core/BoundaryCondition.hpp>

namespace mjolnir
{
extern template class DCDLoader<SimulatorTraits<double, UnlimitedBoundary>>;
extern template class DCDLoader<SimulatorTraits<float,  UnlimitedBoundary>>;
extern template class DCDLoader<SimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class DCDLoader<SimulatorTraits<float,  CuboidalPeriodicBoundary>>;
} // mjolnir
#endif

#endif//MJOLNIR_CORE_DCD_LOADER_HPP
<commit_msg>refactor: try to avoid false positive of linter<commit_after>#ifndef MJOLNIR_CORE_DCD_LOADER_HPP
#define MJOLNIR_CORE_DCD_LOADER_HPP
#include <mjolnir/core/LoaderBase.hpp>
#include <mjolnir/core/System.hpp>
#include <mjolnir/util/logger.hpp>
#include <iostream>
#include <fstream>
#include <iomanip>

namespace mjolnir
{

template<typename traitsT>
class DCDLoader final : public LoaderBase<traitsT>
{
  public:
    using base_type         = LoaderBase<traitsT>;
    using traits_type       = typename base_type::traits_type;
    using real_type         = typename base_type::real_type;
    using coordinate_type   = typename base_type::coordinate_type;
    using system_type       = typename base_type::system_type;

  public:

    explicit DCDLoader(const std::string& filename) : base_type(),
        filename_(filename), file_(filename_, std::ios::binary | std::ios::in),
        has_unitcell_(false)
    {
        if(!file_.good())
        {
            throw_exception<std::runtime_error>("[error] mjolnir::DCDLoader: "
                    "file open error: ", filename_);
        }
    }
    ~DCDLoader() override {}

    void initialize() override
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        // read header region and set `num_particles` and `num_frames`.

        // --------------------------------------------------------------------
        // the first block
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // signature

            this->number_of_frames_ = detail::read_bytes_as<std::int32_t>(file_);

            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // index_of_first
            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // save_interval
            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // total_step
            std::ignore = detail::read_bytes_as<std::int32_t>(file_); // total_chains

            detail::skip_bytes(file_, 4 * sizeof(std::int32_t)); // 4x int flags

            std::ignore = detail::read_bytes_as<float>(file_);
            this->has_unitcell_ = (detail::read_bytes_as<std::int32_t>(file_) == 1);

            detail::skip_bytes(file_, 8 * sizeof(std::int32_t)); // 8x int flags

            std::ignore = detail::read_bytes_as<std::int32_t>(file_);

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);

            MJOLNIR_LOG_NOTICE("There are ", this->number_of_frames_, " frames in ",
                               this->filename_);

            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the first header block is inconsistent");
            }
        }

        // --------------------------------------------------------------------
        // the second block
        {
            const auto block_size_beg  = detail::read_bytes_as<std::int32_t>(file_);
            const auto number_of_lines = detail::read_bytes_as<std::int32_t>(file_);
            for(std::int32_t i=0; i<number_of_lines; ++i)
            {
                std::vector<char> comments(81, '\0');
                file_.read(comments.data(), 80);
                const std::string line(comments.begin(), comments.end());
                MJOLNIR_LOG_NOTICE("comment: ", line);
            }
            const auto block_size_end = detail::read_bytes_as<std::int32_t>(file_);

            if(block_size_beg != block_size_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the second header block is inconsistent");
            }
        }

        // --------------------------------------------------------------------
        // the third block
        {
            const auto block_size_beg  = detail::read_bytes_as<std::int32_t>(file_);
            this->number_of_particles_ = detail::read_bytes_as<std::int32_t>(file_);
            const auto block_size_end  = detail::read_bytes_as<std::int32_t>(file_);

            if(block_size_beg != block_size_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the second header block is inconsistent");
            }
        }
        MJOLNIR_LOG_NOTICE("There are ", this->number_of_particles_,
                           " particles in ", this->filename_);

        buffer_x_.resize(this->number_of_particles_);
        buffer_y_.resize(this->number_of_particles_);
        buffer_z_.resize(this->number_of_particles_);
        return;
    }

    std::size_t num_particles() const noexcept {return number_of_particles_;}
    std::size_t num_frames()    const noexcept {return number_of_frames_;}
    bool        is_eof()        const noexcept {return file_.eof();}

    bool load_next(system_type& sys) override
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        this->read_unitcell_if_needed(sys.boundary());
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            assert(buffer_x_.size() == this->number_of_particles_);
            file_.read(reinterpret_cast<char*>(this->buffer_x_.data()),
                       this->number_of_particles_ * sizeof(float));

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);
            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the coordinate block is inconsistent");
                return false;
            }
        }
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            assert(buffer_y_.size() == this->number_of_particles_);
            file_.read(reinterpret_cast<char*>(this->buffer_y_.data()),
                       this->number_of_particles_ * sizeof(float));

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);
            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the coordinate block is inconsistent");
                return false;
            }
        }
        {
            const auto block_beg = detail::read_bytes_as<std::int32_t>(file_);

            assert(buffer_z_.size() == this->number_of_particles_);
            file_.read(reinterpret_cast<char*>(this->buffer_z_.data()),
                       this->number_of_particles_ * sizeof(float));

            const auto block_end = detail::read_bytes_as<std::int32_t>(file_);
            if(block_beg != block_end)
            {
                MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
                MJOLNIR_LOG_WARN("Size of the coordinate block is inconsistent");
                return false;
            }
        }

        for(std::size_t i=0; i<sys.size(); ++i)
        {
            sys.position(i) = sys.adjust_position(math::make_coordinate<
                coordinate_type>(buffer_x_[i], buffer_y_[i], buffer_z_[i]));
        }
        return true;
    }

    std::string const& filename() const noexcept override {return filename_;}

  private:

    void read_unitcell_if_needed(
        UnlimitedBoundary<real_type, coordinate_type>&) noexcept
    {
        return; // No boundary exists. Do nothing.
    }
    void read_unitcell_if_needed(
        CuboidalPeriodicBoundary<real_type, coordinate_type>& bdry) noexcept
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        if(!this->has_unitcell_)
        {
            MJOLNIR_LOG_WARN("dcd file ", this->filename_, " lacks unit cell "
                             "information.");
            return ;
        }

        const auto block_size_beg = detail::read_bytes_as<std::int32_t>(file_);
        const auto A              = detail::read_bytes_as<double>(file_);
        const auto gamma          = detail::read_bytes_as<double>(file_);
        const auto B              = detail::read_bytes_as<double>(file_);
        const auto beta           = detail::read_bytes_as<double>(file_);
        const auto alpha          = detail::read_bytes_as<double>(file_);
        const auto C              = detail::read_bytes_as<double>(file_);
        const auto block_size_end = detail::read_bytes_as<std::int32_t>(file_);

        if(block_size_beg != block_size_end)
        {
            MJOLNIR_LOG_WARN("DCD file ", filename_, " seems to be broken.");
            MJOLNIR_LOG_WARN("Size of the unitcell block is inconsistent");
        }

        constexpr double half_pi = math::constants<double>::half_pi();

        if((differs(alpha, 90.0) && differs(alpha, std::cos(half_pi))) ||
           (differs(beta,  90.0) && differs(beta,  std::cos(half_pi))) ||
           (differs(gamma, 90.0) && differs(gamma, std::cos(half_pi))))
        {
            MJOLNIR_LOG_WARN("The unit cell is not a rectangle");
            MJOLNIR_LOG_WARN("angle alpha = ", alpha);
            MJOLNIR_LOG_WARN("angle beta  = ", beta);
            MJOLNIR_LOG_WARN("angle gamma = ", gamma);
        }

        // set width; XXX it requires sys.adjust_position later because the
        // original lower bound is unknown (only the width is recorded).
        const auto& lw = bdry.lower_bound();
        bdry.set_upper_bound(math::make_coordinate<coordinate_type>(
                    math::X(lw) + A, math::Y(lw) + B, math::Z(lw) + C));
        return ;
    }

    static bool differs(const double lhs, const double rhs) noexcept
    {
        constexpr double rel_tol = math::rel_tolerance<double>();
        constexpr double abs_tol = math::abs_tolerance<double>();

        return abs_tol                     < std::abs(lhs - rhs) ||
               rel_tol * 0.5 * (lhs + rhs) < std::abs(lhs - rhs);
    }

  private:

    std::string        filename_;
    std::ifstream      file_;
    std::size_t        number_of_frames_;
    std::size_t        number_of_particles_;
    std::vector<float> buffer_x_;
    std::vector<float> buffer_y_;
    std::vector<float> buffer_z_;
    bool               has_unitcell_;
};

} // mjolnir

#ifdef MJOLNIR_SEPARATE_BUILD
#include <mjolnir/core/SimulatorTraits.hpp>
#include <mjolnir/core/BoundaryCondition.hpp>

namespace mjolnir
{
extern template class DCDLoader<SimulatorTraits<double, UnlimitedBoundary>>;
extern template class DCDLoader<SimulatorTraits<float,  UnlimitedBoundary>>;
extern template class DCDLoader<SimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class DCDLoader<SimulatorTraits<float,  CuboidalPeriodicBoundary>>;
} // mjolnir
#endif

#endif//MJOLNIR_CORE_DCD_LOADER_HPP
<|endoftext|>


<commit_before>//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the BasicStore and BasicStoreManager classes.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"

using namespace clang;

typedef llvm::ImmutableMap<const VarDecl*,SVal> VarBindingsTy;

namespace {

class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
  VarBindingsTy::Factory VBFactory;
  GRStateManager& StateMgr;
  MemRegionManager MRMgr;
  const MemRegion* SelfRegion;

public:
  BasicStoreManager(GRStateManager& mgr)
    : StateMgr(mgr), MRMgr(StateMgr.getAllocator()), SelfRegion(0) {}

  ~BasicStoreManager() {}

  SVal Retrieve(Store St, Loc LV, QualType T);
  Store Bind(Store St, Loc LV, SVal V);
  Store Remove(Store St, Loc LV);
  Store getInitialStore();
  MemRegionManager& getRegionManager() { return MRMgr; }

  // FIXME: Investigate what is using this. This method should be removed.
  virtual Loc getLoc(const VarDecl* VD) {
    return loc::MemRegionVal(MRMgr.getVarRegion(VD));
  }

  Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
                            SVal V) {
    return store;
  }

  SVal getLValueVar(const GRState* St, const VarDecl* VD);
  SVal getLValueString(const GRState* St, const StringLiteral* S);
  SVal getLValueCompoundLiteral(const GRState* St,
                                const CompoundLiteralExpr* CL);
  SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal Base);
  SVal getLValueField(const GRState* St, SVal Base, const FieldDecl* D);
  SVal getLValueElement(const GRState* St, SVal Base, SVal Offset);

  /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
  ///  conversions between arrays and pointers.
  SVal ArrayToPointer(SVal Array) { return Array; }

  /// getSelfRegion - Returns the region for the 'self' (Objective-C) or
  ///  'this' object (C++).  When used when analyzing a normal function this
  ///  method returns NULL.
  const MemRegion* getSelfRegion(Store) {
    return SelfRegion;
  }

  Store RemoveDeadBindings(Store store, Stmt* Loc, const LiveVariables& Live,
                           llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                           LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols);

  void iterBindings(Store store, BindingsHandler& f);

  Store BindDecl(Store store, const VarDecl* VD, SVal* InitVal, unsigned Count);

  static inline VarBindingsTy GetVarBindings(Store store) {
    return VarBindingsTy(static_cast<const VarBindingsTy::TreeTy*>(store));
  }

  void print(Store store, std::ostream& Out, const char* nl, const char *sep);
};

} // end anonymous namespace

StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
  return new BasicStoreManager(StMgr);
}

SVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
  return loc::MemRegionVal(MRMgr.getVarRegion(VD));
}

SVal BasicStoreManager::getLValueString(const GRState* St,
                                        const StringLiteral* S) {
  return loc::MemRegionVal(MRMgr.getStringRegion(S));
}

SVal BasicStoreManager::getLValueCompoundLiteral(const GRState* St,
                                                 const CompoundLiteralExpr* CL){
  return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL));
}

SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
                                      SVal Base) {
  return UnknownVal();
}

SVal BasicStoreManager::getLValueField(const GRState* St, SVal Base,
                                       const FieldDecl* D) {

  if (Base.isUnknownOrUndef())
    return Base;

  Loc BaseL = cast<Loc>(Base);
  const MemRegion* BaseR = 0;

  switch(BaseL.getSubKind()) {
    case loc::SymbolValKind:
      BaseR = MRMgr.getSymbolicRegion(cast<loc::SymbolVal>(&BaseL)->getSymbol());
      break;

    case loc::GotoLabelKind:
    case loc::FuncValKind:
      // Technically we can get here if people do funny things with casts.
      return UndefinedVal();

    case loc::MemRegionKind:
      BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
      break;

    case loc::ConcreteIntKind:
      // While these seem funny, this can happen through casts.
      // FIXME: What we should return is the field offset.  For example,
      //  add the field offset to the integer value.  That way funny things
      //  like this work properly:  &(((struct foo *) 0xa)->f)
      return Base;

    default:
      assert ("Unhandled Base.");
      return Base;
  }

  return loc::MemRegionVal(MRMgr.getFieldRegion(D, BaseR));
}

SVal BasicStoreManager::getLValueElement(const GRState* St, SVal Base,
                                         SVal Offset) {
  // Total hack: Just return "Base" for now.
  return Base;
}

SVal BasicStoreManager::Retrieve(Store St, Loc LV, QualType T) {

  if (isa<UnknownVal>(LV))
    return UnknownVal();

  assert (!isa<UndefinedVal>(LV));

  switch (LV.getSubKind()) {

    case loc::MemRegionKind: {
      const VarRegion* R =
        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());

      if (!R)
        return UnknownVal();

      VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
      VarBindingsTy::data_type* T = B.lookup(R->getDecl());
      return T ? *T : UnknownVal();
    }

    case loc::SymbolValKind:
      return UnknownVal();

    case loc::ConcreteIntKind:
      // Some clients may call GetSVal with such an option simply because
      // they are doing a quick scan through their Locs (potentially to
      // invalidate their bindings).  Just return Undefined.
      return UndefinedVal();
    case loc::FuncValKind:
      return LV;

    default:
      assert (false && "Invalid Loc.");
      break;
  }

  return UnknownVal();
}

Store BasicStoreManager::Bind(Store store, Loc LV, SVal V) {
  switch (LV.getSubKind()) {
    case loc::MemRegionKind: {
      const VarRegion* R =
        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return V.isUnknown()
        ? VBFactory.Remove(B, R->getDecl()).getRoot()
        : VBFactory.Add(B, R->getDecl(), V).getRoot();
    }
    default:
      assert ("SetSVal for given Loc type not yet implemented.");
      return store;
  }
}

Store BasicStoreManager::Remove(Store store, Loc LV) {
  switch (LV.getSubKind()) {
    case loc::MemRegionKind: {
      const VarRegion* R =
        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return VBFactory.Remove(B,R->getDecl()).getRoot();
    }
    default:
      assert ("Remove for given Loc type not yet implemented.");
      return store;
  }
}

Store
BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
                          const LiveVariables& Liveness,
                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                          LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) {

  VarBindingsTy B = GetVarBindings(store);
  typedef SVal::symbol_iterator symbol_iterator;

  // Iterate over the variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
    if (Liveness.isLive(Loc, I.getKey())) {
      RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
      SVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        LSymbols.insert(*SI);
    }

  // Scan for live variables and live symbols.
  llvm::SmallPtrSet<const VarRegion*, 10> Marked;

  while (!RegionRoots.empty()) {
    const MemRegion* MR = RegionRoots.back();
    RegionRoots.pop_back();

    while (MR) {
      if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
        LSymbols.insert(SymR->getSymbol());
        break;
      }
      else if (const VarRegion* R = dyn_cast<VarRegion>(MR)) {
        if (Marked.count(R))
          break;

        Marked.insert(R);
        SVal X = GetRegionSVal(store, R);

        // FIXME: We need to handle symbols nested in region definitions.
        for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
          LSymbols.insert(*SI);

        if (!isa<loc::MemRegionVal>(X))
          break;

        const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X);
        RegionRoots.push_back(LVD.getRegion());
        break;
      }
      else if (const SubRegion* R = dyn_cast<SubRegion>(MR))
        MR = R->getSuperRegion();
      else
        break;
    }
  }

  // Remove dead variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
    const VarRegion* R = cast<VarRegion>(MRMgr.getVarRegion(I.getKey()));

    if (!Marked.count(R)) {
      store = Remove(store, loc::MemRegionVal(R));
      SVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        if (!LSymbols.count(*SI)) DSymbols.insert(*SI);
    }
  }

  return store;
}

Store BasicStoreManager::getInitialStore() {

  // The LiveVariables information already has a compilation of all VarDecls
  // used in the function.  Iterate through this set, and "symbolicate"
  // any VarDecl whose value originally comes from outside the function.

  typedef LiveVariables::AnalysisDataTy LVDataTy;
  LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();

  Store St = VBFactory.GetEmptyMap().getRoot();

  for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
    NamedDecl* ND = const_cast<NamedDecl*>(I->first);

    // Handle implicit parameters.
    if (ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
      const Decl& CD = StateMgr.getCodeDecl();
      if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
        if (MD->getSelfDecl() == PD) {
          // Create a region for "self".
          assert (SelfRegion == 0);
          SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
                                                 MRMgr.getHeapRegion());

          St = Bind(St, loc::MemRegionVal(MRMgr.getVarRegion(PD)),
                        loc::MemRegionVal(SelfRegion));
        }
      }
    }
    else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
      // Punt on static variables for now.
      if (VD->getStorageClass() == VarDecl::Static)
        continue;

      // Only handle pointers and integers for now.
      QualType T = VD->getType();
      if (Loc::IsLocType(T) || T->isIntegerType()) {
        // Initialize globals and parameters to symbolic values.
        // Initialize local variables to undefined.
        SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
                  isa<ImplicitParamDecl>(VD))
                 ? SVal::GetSymbolValue(StateMgr.getSymbolManager(), VD)
                 : UndefinedVal();

        St = Bind(St, loc::MemRegionVal(MRMgr.getVarRegion(VD)), X);
      }
    }
  }
  return St;
}

Store BasicStoreManager::BindDecl(Store store, const VarDecl* VD,
                                  SVal* InitVal, unsigned Count) {

  BasicValueFactory& BasicVals = StateMgr.getBasicVals();

  // BasicStore does not model arrays and structs.
  if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
    return store;

  if (VD->hasGlobalStorage()) {
    // Handle variables with global storage: extern, static, PrivateExtern.

    // FIXME:: static variables may have an initializer, but the second time a
    // function is called those values may not be current. Currently, a function
    // will not be called more than once.

    // Static global variables should not be visited here.
    assert(!(VD->getStorageClass() == VarDecl::Static &&
             VD->isFileVarDecl()));

    // Process static variables.
    if (VD->getStorageClass() == VarDecl::Static) {
      // C99: 6.7.8 Initialization
      //  If an object that has static storage duration is not initialized
      //  explicitly, then:
      //   —if it has pointer type, it is initialized to a null pointer;
      //   —if it has arithmetic type, it is initialized to (positive or
      //     unsigned) zero;
      if (!InitVal) {
        QualType T = VD->getType();
        if (Loc::IsLocType(T))
          store = Bind(store, getLoc(VD),
                       loc::ConcreteInt(BasicVals.getValue(0, T)));
        else if (T->isIntegerType())
          store = Bind(store, getLoc(VD),
                       nonloc::ConcreteInt(BasicVals.getValue(0, T)));
        else {
          // assert(0 && "ignore other types of variables");
        }
      } else {
        store = Bind(store, getLoc(VD), *InitVal);
      }
    }
  } else {
    // Process local scalar variables.
    QualType T = VD->getType();
    if (Loc::IsLocType(T) || T->isIntegerType()) {
      SVal V = InitVal ? *InitVal : UndefinedVal();
      store = Bind(store, getLoc(VD), V);
    }
  }

  return store;
}

void BasicStoreManager::print(Store store, std::ostream& Out,
                              const char* nl, const char *sep) {

  VarBindingsTy B = GetVarBindings(store);
  Out << "Variables:" << nl;

  bool isFirst = true;

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
    if (isFirst) isFirst = false;
    else Out << nl;

    Out << ' ' << I.getKey()->getName() << " : ";
    I.getData().print(Out);
  }
}

void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
  VarBindingsTy B = GetVarBindings(store);

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {

    f.HandleBinding(*this, store, MRMgr.getVarRegion(I.getKey()),I.getData());
  }
}

StoreManager::BindingsHandler::~BindingsHandler() {}
<commit_msg>Use the allocator of ExplodedGraph. The whole static analysis module uses it.<commit_after>//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the BasicStore and BasicStoreManager classes.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"

using namespace clang;

typedef llvm::ImmutableMap<const VarDecl*,SVal> VarBindingsTy;

namespace {

class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
  VarBindingsTy::Factory VBFactory;
  GRStateManager& StateMgr;
  MemRegionManager MRMgr;
  const MemRegion* SelfRegion;

public:
  BasicStoreManager(GRStateManager& mgr)
    : VBFactory(mgr.getAllocator()),
      StateMgr(mgr),
      MRMgr(StateMgr.getAllocator()),
      SelfRegion(0) {}

  ~BasicStoreManager() {}

  SVal Retrieve(Store St, Loc LV, QualType T);
  Store Bind(Store St, Loc LV, SVal V);
  Store Remove(Store St, Loc LV);
  Store getInitialStore();
  MemRegionManager& getRegionManager() { return MRMgr; }

  // FIXME: Investigate what is using this. This method should be removed.
  virtual Loc getLoc(const VarDecl* VD) {
    return loc::MemRegionVal(MRMgr.getVarRegion(VD));
  }

  Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
                            SVal V) {
    return store;
  }

  SVal getLValueVar(const GRState* St, const VarDecl* VD);
  SVal getLValueString(const GRState* St, const StringLiteral* S);
  SVal getLValueCompoundLiteral(const GRState* St,
                                const CompoundLiteralExpr* CL);
  SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal Base);
  SVal getLValueField(const GRState* St, SVal Base, const FieldDecl* D);
  SVal getLValueElement(const GRState* St, SVal Base, SVal Offset);

  /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
  ///  conversions between arrays and pointers.
  SVal ArrayToPointer(SVal Array) { return Array; }

  /// getSelfRegion - Returns the region for the 'self' (Objective-C) or
  ///  'this' object (C++).  When used when analyzing a normal function this
  ///  method returns NULL.
  const MemRegion* getSelfRegion(Store) {
    return SelfRegion;
  }

  Store RemoveDeadBindings(Store store, Stmt* Loc, const LiveVariables& Live,
                           llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                           LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols);

  void iterBindings(Store store, BindingsHandler& f);

  Store BindDecl(Store store, const VarDecl* VD, SVal* InitVal, unsigned Count);

  static inline VarBindingsTy GetVarBindings(Store store) {
    return VarBindingsTy(static_cast<const VarBindingsTy::TreeTy*>(store));
  }

  void print(Store store, std::ostream& Out, const char* nl, const char *sep);
};

} // end anonymous namespace

StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
  return new BasicStoreManager(StMgr);
}

SVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
  return loc::MemRegionVal(MRMgr.getVarRegion(VD));
}

SVal BasicStoreManager::getLValueString(const GRState* St,
                                        const StringLiteral* S) {
  return loc::MemRegionVal(MRMgr.getStringRegion(S));
}

SVal BasicStoreManager::getLValueCompoundLiteral(const GRState* St,
                                                 const CompoundLiteralExpr* CL){
  return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL));
}

SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
                                      SVal Base) {
  return UnknownVal();
}

SVal BasicStoreManager::getLValueField(const GRState* St, SVal Base,
                                       const FieldDecl* D) {

  if (Base.isUnknownOrUndef())
    return Base;

  Loc BaseL = cast<Loc>(Base);
  const MemRegion* BaseR = 0;

  switch(BaseL.getSubKind()) {
    case loc::SymbolValKind:
      BaseR = MRMgr.getSymbolicRegion(cast<loc::SymbolVal>(&BaseL)->getSymbol());
      break;

    case loc::GotoLabelKind:
    case loc::FuncValKind:
      // Technically we can get here if people do funny things with casts.
      return UndefinedVal();

    case loc::MemRegionKind:
      BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
      break;

    case loc::ConcreteIntKind:
      // While these seem funny, this can happen through casts.
      // FIXME: What we should return is the field offset.  For example,
      //  add the field offset to the integer value.  That way funny things
      //  like this work properly:  &(((struct foo *) 0xa)->f)
      return Base;

    default:
      assert ("Unhandled Base.");
      return Base;
  }

  return loc::MemRegionVal(MRMgr.getFieldRegion(D, BaseR));
}

SVal BasicStoreManager::getLValueElement(const GRState* St, SVal Base,
                                         SVal Offset) {
  // Total hack: Just return "Base" for now.
  return Base;
}

SVal BasicStoreManager::Retrieve(Store St, Loc LV, QualType T) {

  if (isa<UnknownVal>(LV))
    return UnknownVal();

  assert (!isa<UndefinedVal>(LV));

  switch (LV.getSubKind()) {

    case loc::MemRegionKind: {
      const VarRegion* R =
        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());

      if (!R)
        return UnknownVal();

      VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
      VarBindingsTy::data_type* T = B.lookup(R->getDecl());
      return T ? *T : UnknownVal();
    }

    case loc::SymbolValKind:
      return UnknownVal();

    case loc::ConcreteIntKind:
      // Some clients may call GetSVal with such an option simply because
      // they are doing a quick scan through their Locs (potentially to
      // invalidate their bindings).  Just return Undefined.
      return UndefinedVal();
    case loc::FuncValKind:
      return LV;

    default:
      assert (false && "Invalid Loc.");
      break;
  }

  return UnknownVal();
}

Store BasicStoreManager::Bind(Store store, Loc LV, SVal V) {
  switch (LV.getSubKind()) {
    case loc::MemRegionKind: {
      const VarRegion* R =
        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return V.isUnknown()
        ? VBFactory.Remove(B, R->getDecl()).getRoot()
        : VBFactory.Add(B, R->getDecl(), V).getRoot();
    }
    default:
      assert ("SetSVal for given Loc type not yet implemented.");
      return store;
  }
}

Store BasicStoreManager::Remove(Store store, Loc LV) {
  switch (LV.getSubKind()) {
    case loc::MemRegionKind: {
      const VarRegion* R =
        dyn_cast<VarRegion>(cast<loc::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return VBFactory.Remove(B,R->getDecl()).getRoot();
    }
    default:
      assert ("Remove for given Loc type not yet implemented.");
      return store;
  }
}

Store
BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
                          const LiveVariables& Liveness,
                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                          LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) {

  VarBindingsTy B = GetVarBindings(store);
  typedef SVal::symbol_iterator symbol_iterator;

  // Iterate over the variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
    if (Liveness.isLive(Loc, I.getKey())) {
      RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
      SVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        LSymbols.insert(*SI);
    }

  // Scan for live variables and live symbols.
  llvm::SmallPtrSet<const VarRegion*, 10> Marked;

  while (!RegionRoots.empty()) {
    const MemRegion* MR = RegionRoots.back();
    RegionRoots.pop_back();

    while (MR) {
      if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
        LSymbols.insert(SymR->getSymbol());
        break;
      }
      else if (const VarRegion* R = dyn_cast<VarRegion>(MR)) {
        if (Marked.count(R))
          break;

        Marked.insert(R);
        SVal X = GetRegionSVal(store, R);

        // FIXME: We need to handle symbols nested in region definitions.
        for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
          LSymbols.insert(*SI);

        if (!isa<loc::MemRegionVal>(X))
          break;

        const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X);
        RegionRoots.push_back(LVD.getRegion());
        break;
      }
      else if (const SubRegion* R = dyn_cast<SubRegion>(MR))
        MR = R->getSuperRegion();
      else
        break;
    }
  }

  // Remove dead variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
    const VarRegion* R = cast<VarRegion>(MRMgr.getVarRegion(I.getKey()));

    if (!Marked.count(R)) {
      store = Remove(store, loc::MemRegionVal(R));
      SVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        if (!LSymbols.count(*SI)) DSymbols.insert(*SI);
    }
  }

  return store;
}

Store BasicStoreManager::getInitialStore() {

  // The LiveVariables information already has a compilation of all VarDecls
  // used in the function.  Iterate through this set, and "symbolicate"
  // any VarDecl whose value originally comes from outside the function.

  typedef LiveVariables::AnalysisDataTy LVDataTy;
  LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();

  Store St = VBFactory.GetEmptyMap().getRoot();

  for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
    NamedDecl* ND = const_cast<NamedDecl*>(I->first);

    // Handle implicit parameters.
    if (ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
      const Decl& CD = StateMgr.getCodeDecl();
      if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
        if (MD->getSelfDecl() == PD) {
          // Create a region for "self".
          assert (SelfRegion == 0);
          SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
                                                 MRMgr.getHeapRegion());

          St = Bind(St, loc::MemRegionVal(MRMgr.getVarRegion(PD)),
                        loc::MemRegionVal(SelfRegion));
        }
      }
    }
    else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
      // Punt on static variables for now.
      if (VD->getStorageClass() == VarDecl::Static)
        continue;

      // Only handle pointers and integers for now.
      QualType T = VD->getType();
      if (Loc::IsLocType(T) || T->isIntegerType()) {
        // Initialize globals and parameters to symbolic values.
        // Initialize local variables to undefined.
        SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
                  isa<ImplicitParamDecl>(VD))
                 ? SVal::GetSymbolValue(StateMgr.getSymbolManager(), VD)
                 : UndefinedVal();

        St = Bind(St, loc::MemRegionVal(MRMgr.getVarRegion(VD)), X);
      }
    }
  }
  return St;
}

Store BasicStoreManager::BindDecl(Store store, const VarDecl* VD,
                                  SVal* InitVal, unsigned Count) {

  BasicValueFactory& BasicVals = StateMgr.getBasicVals();

  // BasicStore does not model arrays and structs.
  if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
    return store;

  if (VD->hasGlobalStorage()) {
    // Handle variables with global storage: extern, static, PrivateExtern.

    // FIXME:: static variables may have an initializer, but the second time a
    // function is called those values may not be current. Currently, a function
    // will not be called more than once.

    // Static global variables should not be visited here.
    assert(!(VD->getStorageClass() == VarDecl::Static &&
             VD->isFileVarDecl()));

    // Process static variables.
    if (VD->getStorageClass() == VarDecl::Static) {
      // C99: 6.7.8 Initialization
      //  If an object that has static storage duration is not initialized
      //  explicitly, then:
      //   —if it has pointer type, it is initialized to a null pointer;
      //   —if it has arithmetic type, it is initialized to (positive or
      //     unsigned) zero;
      if (!InitVal) {
        QualType T = VD->getType();
        if (Loc::IsLocType(T))
          store = Bind(store, getLoc(VD),
                       loc::ConcreteInt(BasicVals.getValue(0, T)));
        else if (T->isIntegerType())
          store = Bind(store, getLoc(VD),
                       nonloc::ConcreteInt(BasicVals.getValue(0, T)));
        else {
          // assert(0 && "ignore other types of variables");
        }
      } else {
        store = Bind(store, getLoc(VD), *InitVal);
      }
    }
  } else {
    // Process local scalar variables.
    QualType T = VD->getType();
    if (Loc::IsLocType(T) || T->isIntegerType()) {
      SVal V = InitVal ? *InitVal : UndefinedVal();
      store = Bind(store, getLoc(VD), V);
    }
  }

  return store;
}

void BasicStoreManager::print(Store store, std::ostream& Out,
                              const char* nl, const char *sep) {

  VarBindingsTy B = GetVarBindings(store);
  Out << "Variables:" << nl;

  bool isFirst = true;

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
    if (isFirst) isFirst = false;
    else Out << nl;

    Out << ' ' << I.getKey()->getName() << " : ";
    I.getData().print(Out);
  }
}

void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
  VarBindingsTy B = GetVarBindings(store);

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {

    f.HandleBinding(*this, store, MRMgr.getVarRegion(I.getKey()),I.getData());
  }
}

StoreManager::BindingsHandler::~BindingsHandler() {}
<|endoftext|>


<commit_before>// Copyright 2012-13 Bifrost Entertainment. All rights reserved.

#include "Graphics/Label.h"
#include "Graphics/Renderer.h"
#include "Graphics/SceneGraph.h"
#include "Graphics/ShaderManager.h"
#include "Graphics/SpriteBatch.h"

#ifdef GL_ES_VERSION_2_0
#	include "Graphics/Shaders/Shaders.h"
#else
#	define fixed2d_vsh "Shaders/Fixed2D.vsh"
#	define fixed2d_fsh "Shaders/Fixed2D.fsh"
#endif

namespace Renderer
{
	extern const int kNumSprites = 256;  ///< Hard-coded limit on number of sprites.
	unsigned int g_index_buffer = 0;     ///< Index buffer object.

	namespace
	{
		/// Default vertex indices (currently limited to \c kNumSprites sprites).
		template<typename T>
		const T* default_indices(T *buffer)
		{
			int i = -1;
			for (int j = 0; j < kNumSprites * 4; j += 4)
			{
				buffer[++i] = j;
				buffer[++i] = j + 1;
				buffer[++i] = j + 2;
				buffer[++i] = j + 2;
				buffer[++i] = j + 3;
				buffer[++i] = j;
			}
			return buffer;
		}
	}

	bool init()
	{
	#ifdef __glew_h__
		GLenum err = glewInit();
		if (err != GLEW_OK)
		{
			R_ERROR("[Rainbow] Failed to initialise GLEW: %s\n",
			        glewGetErrorString(err));
			return false;
		}
	#endif

		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

		glEnable(GL_CULL_FACE);
		glDisable(GL_STENCIL_TEST);
		glDisable(GL_DEPTH_TEST);

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		const char *shaders[] = { fixed2d_vsh, fixed2d_fsh };
		ShaderManager::Instance = new ShaderManager(shaders, 2);
		if (!*ShaderManager::Instance)
		{
			delete ShaderManager::Instance;
			return false;
		}

		TextureManager::Instance = new TextureManager();

		unsigned short buffer[kNumSprites * 6];
		glGenBuffers(1, &g_index_buffer);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_index_buffer);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(buffer),
		             default_indices(buffer), GL_STATIC_DRAW);

		return glGetError() == GL_NO_ERROR;
	}

	void release()
	{
		if (g_index_buffer)
		{
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
			glDeleteBuffers(1, &g_index_buffer);
		}
		glUseProgram(0);
		delete TextureManager::Instance;
		delete ShaderManager::Instance;
	}

	void clear()
	{
		glClear(GL_COLOR_BUFFER_BIT);
	}

	void resize(const unsigned int width, const unsigned int height)
	{
		ShaderManager::Instance->set(width, height);
		ShaderManager::Instance->reset();
		glViewport(0, 0, width, height);

		R_ASSERT(glGetError() == GL_NO_ERROR,
		         "Failed to initialise OpenGL viewport");
	}

	void draw(const Label &label)
	{
		label.font().bind();
		draw(label.vertex_array());
	}

	void draw(const SceneGraph::Node &node)
	{
		if (!node.enabled)
			return;

		switch (node.type)
		{
			case SceneGraph::Node::DrawableNode:
				node.drawable->draw();
				break;
			case SceneGraph::Node::LabelNode:
				Renderer::draw(*node.label);
				break;
			case SceneGraph::Node::SpriteBatchNode:
				Renderer::draw(*node.sprite_batch);
				break;
			default:
				break;
		}
		for (auto child : node.children)
			draw(*child);
	}

	void draw(const SpriteBatch &batch)
	{
		batch.texture().bind();
		draw(batch.vertex_array());
	}

	void draw(const VertexArray &array)
	{
		BindVertexArray bind(array);
		glDrawElements(GL_TRIANGLES, array.count, GL_UNSIGNED_SHORT, nullptr);
		R_ASSERT(glGetError() == GL_NO_ERROR, "Failed to draw buffer");
	}

	void draw_elements(const SpriteVertex *vertices, const unsigned int count)
	{
		glVertexAttribPointer(
				Shader::COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE,
				sizeof(SpriteVertex), &vertices->color);
		glVertexAttribPointer(
				Shader::TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex),
				&vertices->texcoord);
		glVertexAttribPointer(
				Shader::VERTEX, 2, GL_FLOAT, GL_TRUE, sizeof(SpriteVertex),
				&vertices->position);

		glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, nullptr);

		R_ASSERT(glGetError() == GL_NO_ERROR, "Failed to draw elements");
	}
}
<commit_msg>Generate indices at compile-time.<commit_after>// Copyright 2012-13 Bifrost Entertainment. All rights reserved.

#include "Graphics/Label.h"
#include "Graphics/Renderer.h"
#include "Graphics/SceneGraph.h"
#include "Graphics/ShaderManager.h"
#include "Graphics/SpriteBatch.h"

#ifdef GL_ES_VERSION_2_0
#	include "Graphics/Shaders/Shaders.h"
#else
#	define fixed2d_vsh "Shaders/Fixed2D.vsh"
#	define fixed2d_fsh "Shaders/Fixed2D.fsh"
#endif

#define S4(i)       S1((i))  //S1((i) +   1),   S1((i) +   2),   S1((i) +   3)
#define S16(i)      S4((i)),   S4((i) +   4),   S4((i) +   8),   S4((i) +  12)
#define S64(i)     S16((i)),  S16((i) +  16),  S16((i) +  32),  S16((i) +  48)
#define S256(i)    S64((i)),  S64((i) +  64),  S64((i) + 128),  S64((i) + 192)
#define S1024(i)  S256((i)), S256((i) + 256), S256((i) + 512), S256((i) + 768)

namespace Renderer
{
	extern const int kNumSprites = 256;  ///< Hard-coded limit on number of sprites.
	unsigned int g_index_buffer = 0;     ///< Index buffer object.

	bool init()
	{
	#ifdef __glew_h__
		GLenum err = glewInit();
		if (err != GLEW_OK)
		{
			R_ERROR("[Rainbow] Failed to initialise GLEW: %s\n",
			        glewGetErrorString(err));
			return false;
		}
	#endif

		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

		glEnable(GL_CULL_FACE);
		glDisable(GL_STENCIL_TEST);
		glDisable(GL_DEPTH_TEST);

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		const char *shaders[] = { fixed2d_vsh, fixed2d_fsh };
		ShaderManager::Instance = new ShaderManager(shaders, 2);
		if (!*ShaderManager::Instance)
		{
			delete ShaderManager::Instance;
			return false;
		}

		TextureManager::Instance = new TextureManager();

		const unsigned short kDefaultIndices[] = {
		#define S1(i) (i), (i) + 1, (i) + 2, (i) + 2, (i) + 3, (i)
			S256(0)
		#undef S1
		};
		glGenBuffers(1, &g_index_buffer);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_index_buffer);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kDefaultIndices),
		             kDefaultIndices, GL_STATIC_DRAW);

		return glGetError() == GL_NO_ERROR;
	}

	void release()
	{
		if (g_index_buffer)
		{
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
			glDeleteBuffers(1, &g_index_buffer);
		}
		glUseProgram(0);
		delete TextureManager::Instance;
		delete ShaderManager::Instance;
	}

	void clear()
	{
		glClear(GL_COLOR_BUFFER_BIT);
	}

	void resize(const unsigned int width, const unsigned int height)
	{
		ShaderManager::Instance->set(width, height);
		ShaderManager::Instance->reset();
		glViewport(0, 0, width, height);

		R_ASSERT(glGetError() == GL_NO_ERROR,
		         "Failed to initialise OpenGL viewport");
	}

	void draw(const Label &label)
	{
		label.font().bind();
		draw(label.vertex_array());
	}

	void draw(const SceneGraph::Node &node)
	{
		if (!node.enabled)
			return;

		switch (node.type)
		{
			case SceneGraph::Node::DrawableNode:
				node.drawable->draw();
				break;
			case SceneGraph::Node::LabelNode:
				Renderer::draw(*node.label);
				break;
			case SceneGraph::Node::SpriteBatchNode:
				Renderer::draw(*node.sprite_batch);
				break;
			default:
				break;
		}
		for (auto child : node.children)
			draw(*child);
	}

	void draw(const SpriteBatch &batch)
	{
		batch.texture().bind();
		draw(batch.vertex_array());
	}

	void draw(const VertexArray &array)
	{
		BindVertexArray bind(array);
		glDrawElements(GL_TRIANGLES, array.count, GL_UNSIGNED_SHORT, nullptr);
		R_ASSERT(glGetError() == GL_NO_ERROR, "Failed to draw buffer");
	}

	void draw_elements(const SpriteVertex *vertices, const unsigned int count)
	{
		glVertexAttribPointer(
				Shader::COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE,
				sizeof(SpriteVertex), &vertices->color);
		glVertexAttribPointer(
				Shader::TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex),
				&vertices->texcoord);
		glVertexAttribPointer(
				Shader::VERTEX, 2, GL_FLOAT, GL_TRUE, sizeof(SpriteVertex),
				&vertices->position);

		glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, nullptr);

		R_ASSERT(glGetError() == GL_NO_ERROR, "Failed to draw elements");
	}
}
<|endoftext|>