<commit_before>#include "NFmiDataMatrixUtils.h"
#include "NFmiQueryDataUtil.h"
#include "NFmiInterpolation.h"

namespace
{
    double FixIndexOnEdges(double index, size_t matrixSize)
    {
        const double epsilon = 0.000001;
        if(index < 0 && NFmiQueryDataUtil::IsEqualEnough(index, 0., epsilon))
            index = 0;
        else
        {
            double xMaxLimit = matrixSize - 1.;
            if(index >= xMaxLimit && NFmiQueryDataUtil::IsEqualEnough(index, xMaxLimit, epsilon))
                index = xMaxLimit - epsilon;
        }
        return index;
    }
}

namespace DataMatrixUtils
{
    // Tämä funktio laskee interpoloidun arvon matriisin datasta.
    // Annettu piste on halutussa suhteellisessa koordinaatistossa (esim. 0,0  -  1,1 maailmassa)
    // ja kyseinen koordinaatisto (rect-olio) pitää antaa parametrina.
    // HUOM! rect-olio ja matriisi ovat y-akselin suhteen käänteisiä!
    float InterpolatedValue(const NFmiDataMatrix<float>& m, const NFmiPoint& thePoint,
        const NFmiRect& theRelativeCoords,
        FmiParameterName theParamId,
        bool fDontInvertY,
        FmiInterpolationMethod interp)
    {
        float value = kFloatMissing;
        double xInd =
            ((m.NX() - 1) * (thePoint.X() - theRelativeCoords.Left())) / theRelativeCoords.Width();
        // yInd-laskussa pitää y-akseli kääntää
        double yInd =
            fDontInvertY
            ? ((m.NY() - 1) * (thePoint.Y() - theRelativeCoords.Top())) / theRelativeCoords.Height()
            : ((m.NY() - 1) *
            (theRelativeCoords.Height() - (thePoint.Y() - theRelativeCoords.Top()))) /
            theRelativeCoords.Height();
        // xInd ja yInd voivat mennä juuri pikkuisen yli rajojen ja laskut menevät muuten pieleen, mutta
        // tässä korjataan indeksejä juuri pikkuisen, että laskut menevät näissä tapauksissa läpi ja
        // riittävän oikein arvoin.
        xInd = ::FixIndexOnEdges(xInd, m.NX());
        yInd = ::FixIndexOnEdges(yInd, m.NY());

        int x1 = static_cast<int>(std::floor(xInd));
        int y1 = static_cast<int>(std::floor(yInd));
        int x2 = x1 + 1;
        int y2 = y1 + 1;
        if(x1 >= 0 && x2 < static_cast<int>(m.NX()) && y1 >= 0 && y2 < static_cast<int>(m.NY()))
        {  // lasketaan tulos vain jos ollaan matriisin sisällä, tähän voisi reunoille laskea erikois
           // arvoja jos haluaa
            double xFraction = xInd - x1;
            double yFraction = yInd - y1;
            if(interp == kNearestPoint)
                return m.At(FmiRound(xInd), FmiRound(yInd));
            else
            {
                if(theParamId == kFmiWindDirection || theParamId == kFmiWaveDirection)
                    value = static_cast<float>(NFmiInterpolation::ModBiLinear(
                        xFraction, yFraction, m.At(x1, y2), m.At(x2, y2), m.At(x1, y1), m.At(x2, y1), 360));
                else if(theParamId == kFmiWindVectorMS)
                    value = static_cast<float>(NFmiInterpolation::WindVector(
                        xFraction, yFraction, m.At(x1, y2), m.At(x2, y2), m.At(x1, y1), m.At(x2, y1)));
                else
                    value = static_cast<float>(NFmiInterpolation::BiLinear(
                        xFraction, yFraction, m.At(x1, y2), m.At(x2, y2), m.At(x1, y1), m.At(x2, y1)));
            }
        }
        return value;
    }

    void PrettyPrint(std::ostream& s, const NFmiDataMatrix<float>& m, bool printYInverted, bool printIndexAxies)
    {
        typedef typename NFmiDataMatrix<float>::size_type sz_type;
        sz_type rows = m.NY();
        sz_type columns = m.NX();

        s << static_cast<unsigned int>(columns) << " " << static_cast<unsigned int>(rows) << std::endl;

        if(printYInverted == false)
        {
            for(sz_type j = 0; j < rows; j++)
            {
                for(sz_type i = 0; i < columns; i++)
                    s << m[i][j] << " ";
                s << std::endl;
            }
        }
        else
        {  // tulostus käänteisessä rivi-järjestyksessä
            for(sz_type j = rows - 1; j >= 0; j--)
            {
                if(printIndexAxies) s << j << "\t";
                for(sz_type i = 0; i < columns; i++)
                    s << m[i][j] << " ";
                s << std::endl;

                if(j == 0)  // luulen että koska j on unsigned tyyppinen, pitää tässä tarkastella 0-riviä,
                             // koska for-loopissa j-- lauseke ei ikinä vie j:n arvoa negatiiviseksi
                             // (kierähtää 0:sta tosi isoksi luvuksi)
                {
                    if(printIndexAxies)
                    {
                        for(sz_type i = 0; i < columns; i++)
                            s << i << " ";
                    }
                    break;
                }
            }
        }
    }

}
<commit_msg>Fixed eternal loop<commit_after>#include "NFmiDataMatrixUtils.h"
#include "NFmiInterpolation.h"
#include "NFmiQueryDataUtil.h"

namespace
{
double FixIndexOnEdges(double index, size_t matrixSize)
{
  const double epsilon = 0.000001;
  if (index < 0 && NFmiQueryDataUtil::IsEqualEnough(index, 0., epsilon))
    index = 0;
  else
  {
    double xMaxLimit = matrixSize - 1.;
    if (index >= xMaxLimit && NFmiQueryDataUtil::IsEqualEnough(index, xMaxLimit, epsilon))
      index = xMaxLimit - epsilon;
  }
  return index;
}
}  // namespace

namespace DataMatrixUtils
{
// Tämä funktio laskee interpoloidun arvon matriisin datasta.
// Annettu piste on halutussa suhteellisessa koordinaatistossa (esim. 0,0  -  1,1 maailmassa)
// ja kyseinen koordinaatisto (rect-olio) pitää antaa parametrina.
// HUOM! rect-olio ja matriisi ovat y-akselin suhteen käänteisiä!
float InterpolatedValue(const NFmiDataMatrix<float>& m,
                        const NFmiPoint& thePoint,
                        const NFmiRect& theRelativeCoords,
                        FmiParameterName theParamId,
                        bool fDontInvertY,
                        FmiInterpolationMethod interp)
{
  float value = kFloatMissing;
  double xInd =
      ((m.NX() - 1) * (thePoint.X() - theRelativeCoords.Left())) / theRelativeCoords.Width();
  // yInd-laskussa pitää y-akseli kääntää
  double yInd =
      fDontInvertY
          ? ((m.NY() - 1) * (thePoint.Y() - theRelativeCoords.Top())) / theRelativeCoords.Height()
          : ((m.NY() - 1) *
             (theRelativeCoords.Height() - (thePoint.Y() - theRelativeCoords.Top()))) /
                theRelativeCoords.Height();
  // xInd ja yInd voivat mennä juuri pikkuisen yli rajojen ja laskut menevät muuten pieleen, mutta
  // tässä korjataan indeksejä juuri pikkuisen, että laskut menevät näissä tapauksissa läpi ja
  // riittävän oikein arvoin.
  xInd = ::FixIndexOnEdges(xInd, m.NX());
  yInd = ::FixIndexOnEdges(yInd, m.NY());

  int x1 = static_cast<int>(std::floor(xInd));
  int y1 = static_cast<int>(std::floor(yInd));
  int x2 = x1 + 1;
  int y2 = y1 + 1;
  if (x1 >= 0 && x2 < static_cast<int>(m.NX()) && y1 >= 0 && y2 < static_cast<int>(m.NY()))
  {  // lasketaan tulos vain jos ollaan matriisin sisällä, tähän voisi reunoille laskea erikois
     // arvoja jos haluaa
    double xFraction = xInd - x1;
    double yFraction = yInd - y1;
    if (interp == kNearestPoint)
      return m.At(FmiRound(xInd), FmiRound(yInd));
    else
    {
      if (theParamId == kFmiWindDirection || theParamId == kFmiWaveDirection)
        value = static_cast<float>(NFmiInterpolation::ModBiLinear(
            xFraction, yFraction, m.At(x1, y2), m.At(x2, y2), m.At(x1, y1), m.At(x2, y1), 360));
      else if (theParamId == kFmiWindVectorMS)
        value = static_cast<float>(NFmiInterpolation::WindVector(
            xFraction, yFraction, m.At(x1, y2), m.At(x2, y2), m.At(x1, y1), m.At(x2, y1)));
      else
        value = static_cast<float>(NFmiInterpolation::BiLinear(
            xFraction, yFraction, m.At(x1, y2), m.At(x2, y2), m.At(x1, y1), m.At(x2, y1)));
    }
  }
  return value;
}

void PrettyPrint(std::ostream& s,
                 const NFmiDataMatrix<float>& m,
                 bool printYInverted,
                 bool printIndexAxies)
{
  typedef typename NFmiDataMatrix<float>::size_type sz_type;
  sz_type rows = m.NY();
  sz_type columns = m.NX();

  s << static_cast<unsigned int>(columns) << " " << static_cast<unsigned int>(rows) << std::endl;

  if (printYInverted == false)
  {
    for (sz_type j = 0; j < rows; j++)
    {
      for (sz_type i = 0; i < columns; i++)
        s << m[i][j] << " ";
      s << std::endl;
    }
  }
  else
  {  // tulostus käänteisessä rivi-järjestyksessä
    for (long j = rows - 1; j >= 0; j--)
    {
      if (printIndexAxies) s << j << "\t";
      for (sz_type i = 0; i < columns; i++)
        s << m[i][j] << " ";
      s << std::endl;

      if (j == 0)  // luulen että koska j on unsigned tyyppinen, pitää tässä tarkastella 0-riviä,
                   // koska for-loopissa j-- lauseke ei ikinä vie j:n arvoa negatiiviseksi
                   // (kierähtää 0:sta tosi isoksi luvuksi)
      {
        if (printIndexAxies)
        {
          for (sz_type i = 0; i < columns; i++)
            s << i << " ";
        }
        break;
      }
    }
  }
}

}  // namespace DataMatrixUtils
<|endoftext|>


<commit_before><commit_msg>Improve the arg_order test just a little bit<commit_after><|endoftext|>


<commit_before>#include "targetver.h"
#include "spipc.h"

#include <stdio.h>
#include <tchar.h>
#include <thread>

namespace spipc { namespace testing {
class Memory_Transport: public sprot::Transport_Interface
{
    public:

        Memory_Transport();
        virtual size_t read(void* buf, size_t buf_size, size_t timeout = infinite_wait);
        virtual size_t write(const void* buf, size_t buf_size, size_t timeout = infinite_wait);

    private:

        std::vector <unsigned char> buf_;
        static const size_t buf_reserve_ = 1024 * 1024;
        std::recursive_mutex write_protector_;
        std::condition_variable data_available_;
        std::condition_variable buffer_empty_;

        void reset();
};

Memory_Transport::Memory_Transport()
{
    reset();
}

void Memory_Transport::reset()
{
    std::vector<unsigned char> empty;
    buf_.swap(empty);
    buf_.reserve(buf_reserve_);
}

size_t Memory_Transport::write(const void* buf, size_t buf_size, size_t timeout)
{
    std::lock_guard<std::recursive_mutex> lock(write_protector_);
    static std::mutex mutex;
    std::unique_lock<std::mutex> buffer_empty_lock(mutex);

    if (buf_.size() != 0)
        buffer_empty_.wait(buffer_empty_lock);

    buf_.insert(buf_.end(), (unsigned char*)buf, (unsigned char*)buf + buf_size);
    data_available_.notify_all();
    return buf_size;
}

size_t Memory_Transport::read(void* buf, size_t buf_size, size_t timeout)
{
    static std::mutex mutex;
    std::unique_lock<std::mutex> data_avail_lock(mutex);

    data_available_.wait(data_avail_lock);

    size_t read_bytes = buf_size > buf_.size() ? buf_.size() : buf_size;
    memcpy(buf, &(buf_[0]), read_bytes);
    buf_.resize(0);

    buffer_empty_.notify_all();

    return read_bytes;
}

std::recursive_mutex g_test_mutex;
std::vector<std::string> g_written_items;

void th1_mem_trans_test(Memory_Transport* trans)
{
    static unsigned counter = 0;
    srand(std::this_thread::get_id().hash());

    std::vector<std::string> written_items;

    while (counter++ < 10)
    {
        int rnd_sz = 1 + rand() % 12;

        std::vector<char> to_write;
        for (int i = 0; i < rnd_sz; ++i)
            to_write.push_back(65 + rand() % 20);
        to_write.push_back(0);

        char* write_buf = &(*to_write.begin());
        printf("Writing: %s (%d bytes)\n", write_buf, rnd_sz + 1);

        trans->write(write_buf, rnd_sz + 1);
        written_items.push_back(write_buf);

        //std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    std::lock_guard<std::recursive_mutex> lock(g_test_mutex);
    g_written_items.insert(g_written_items.end(), written_items.begin(), written_items.end());
}

std::vector<std::string> g_read_items;

void th2_mem_trans_test(Memory_Transport* trans)
{
    static unsigned counter = 0;
    srand(std::this_thread::get_id().hash());

    std::vector<std::string> read_items;

    while (counter++ < 10)
    {
        char read_buf[256];
        memset(read_buf, 0, sizeof(read_buf));
        trans->read(read_buf, sizeof(read_buf));

        read_items.push_back(read_buf);
        printf("Reading: %s\n", read_buf);

        //std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    std::lock_guard<std::recursive_mutex> lock(g_test_mutex);
    g_read_items.insert(g_read_items.end(), read_items.begin(), read_items.end());
}

bool N_threads_mem_transport_test()
{
    Memory_Transport trans;

    std::thread writer(th1_mem_trans_test, &trans);
    std::thread reader(th2_mem_trans_test, &trans);

    writer.join();
    reader.join();

    if (g_read_items.size() != g_written_items.size())
    {
        printf("ERROR: number of read items != number of written items.");
        return false;
    }

    if (g_read_items.size() == 0)
    {
        printf("ERROR: number of read items is 0.");
        return false;
    }

    for (std::vector<std::string>::iterator i = g_written_items.begin(); i != g_written_items.end();)
    {
        for (std::vector<std::string>::iterator j = g_read_items.begin(); j != g_read_items.end();)
        {
            if (*i == *j)
            {
                g_written_items.erase(i);
                g_read_items.erase(j);

                i = g_written_items.begin();
                j = g_read_items.begin();
            }
            else
            {
                ++i;
                ++j;
            }
        }
    }

    if (g_read_items.size() != g_written_items.size())
    {
        printf("ERROR: there was a corruption during read/write because not all written items were read.\n");

        printf("Leftovers in g_read_items:\n");
        for (size_t i = 0; i < g_read_items.size(); ++i)
            printf("%s ", g_read_items[i].c_str());

        printf("\nLeftovers in g_written_items:\n");
        for (size_t i = 0; i < g_written_items.size(); ++i)
            printf("%s ", g_written_items[i].c_str());
        printf("\n");

        return false;
    }

    if (g_read_items.size() != 0)
    {
        printf("ERROR: read/write problem detected.\n");

        printf("Leftovers in g_read_items:\n");
        for (size_t i = 0; i < g_read_items.size(); ++i)
            printf("%s ", g_read_items[i].c_str());

        printf("\nLeftovers in g_written_items:\n");
        for (size_t i = 0; i < g_written_items.size(); ++i)
            printf("%s ", g_written_items[i].c_str());
        printf("\n");

        return false;
    }

    return true;
}

void run_all_tests()
{
    if (!N_threads_mem_transport_test())
        printf("N_threads_mem_transport_test failed.\n");

    printf("tests finished OK.\n");
}

}};

int _tmain(int argc, _TCHAR* argv[])
{
    spipc::testing::run_all_tests();
	return 0;
}
<commit_msg>Fixed race conditions / deadlocks, extended mem trans test.<commit_after>#include "targetver.h"
#include "spipc.h"

#include <stdio.h>
#include <tchar.h>
#include <thread>
#include <atomic>

namespace spipc { namespace testing {
class Memory_Transport: public sprot::Transport_Interface
{
    public:

        Memory_Transport();
        virtual size_t read(void* buf, size_t buf_size, size_t timeout = infinite_wait);
        virtual size_t write(const void* buf, size_t buf_size, size_t timeout = infinite_wait);

    private:

        std::vector <unsigned char> buf_;
        static const size_t buf_reserve_ = 1024 * 1024;
        std::mutex condition_mutex_;
        std::condition_variable data_available_;
        std::condition_variable buffer_empty_;

        void reset();
};

Memory_Transport::Memory_Transport()
{
    reset();
}

void Memory_Transport::reset()
{
    std::lock_guard<std::mutex> lock(condition_mutex_);

    std::vector<unsigned char> empty;
    buf_.swap(empty);
    buf_.reserve(buf_reserve_);
}

size_t Memory_Transport::write(const void* buf, size_t buf_size, size_t timeout)
{
    std::unique_lock<std::mutex> lock(condition_mutex_);

    while (buf_.size() != 0)
        if (buffer_empty_.wait_for(lock, std::chrono::milliseconds(timeout)) == std::cv_status::timeout)
        {
            data_available_.notify_all();
            return 0;
        }

    buf_.insert(buf_.end(), (unsigned char*)buf, (unsigned char*)buf + buf_size);
    data_available_.notify_all();

    return buf_size;
}

size_t Memory_Transport::read(void* buf, size_t buf_size, size_t timeout)
{
    std::unique_lock<std::mutex> lock(condition_mutex_);

    while (buf_.size() == 0)
        if (data_available_.wait_for(lock, std::chrono::milliseconds(timeout)) == std::cv_status::timeout)
        {
            buffer_empty_.notify_all();
            return 0;
        }

    size_t read_bytes = buf_size > buf_.size() ? buf_.size() : buf_size;
    memcpy(buf, &(buf_[0]), read_bytes);
    buf_.resize(0);
    buffer_empty_.notify_all();

    return read_bytes;
}

std::recursive_mutex g_test_mutex;
std::vector<std::string> g_written_items;

void th1_mem_trans_test(Memory_Transport* trans)
{
    srand(std::this_thread::get_id().hash());

    std::vector<std::string> written_items;
    static std::atomic_int counter{0};
    while (counter++ < 100000)
    {
        int rnd_sz = 1 + rand() % 12;

        std::vector<char> to_write;
        for (int i = 0; i < rnd_sz; ++i)
            to_write.push_back(65 + rand() % 20);
        to_write.push_back(0);

        char* write_buf = &(*to_write.begin());
        //printf("Writing: %s (%d bytes)\n", write_buf, rnd_sz + 1);

        trans->write(write_buf, rnd_sz + 1);
        written_items.push_back(write_buf);

        //std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    std::lock_guard<std::recursive_mutex> lock(g_test_mutex);
    g_written_items.insert(g_written_items.end(), written_items.begin(), written_items.end());
}

std::vector<std::string> g_read_items;
//volatile bool g_stop_reading = false;

void th2_mem_trans_test(Memory_Transport* trans)
{
    static std::atomic_int counter{0};
    srand(std::this_thread::get_id().hash());

    std::vector<std::string> read_items;

    while (counter++ < 100000)
    {
        char read_buf[256];
        memset(read_buf, 0, sizeof(read_buf));
        trans->read(read_buf, sizeof(read_buf), 1000);

        //if (g_stop_reading)
            //break;

        read_items.push_back(read_buf);
        //printf("Reading: %s\n", read_buf);

        //std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    std::lock_guard<std::recursive_mutex> lock(g_test_mutex);
    g_read_items.insert(g_read_items.end(), read_items.begin(), read_items.end());
}

bool N_threads_mem_transport_test()
{
    Memory_Transport trans;

    std::thread writer(th1_mem_trans_test, &trans);
    std::thread reader(th2_mem_trans_test, &trans);
    std::thread writer2(th1_mem_trans_test, &trans);
    std::thread reader2(th2_mem_trans_test, &trans);
    std::thread writer3(th1_mem_trans_test, &trans);
    std::thread reader3(th2_mem_trans_test, &trans);
    std::thread writer4(th1_mem_trans_test, &trans);
    std::thread writer5(th1_mem_trans_test, &trans);
    std::thread writer6(th1_mem_trans_test, &trans);

    writer.join();
    writer2.join();
    writer3.join();
    writer4.join();
    writer5.join();
    writer6.join();

    //g_stop_reading = true;

    reader.join();
    reader2.join();
    reader3.join();

    if (g_read_items.size() != g_written_items.size())
    {
        printf("ERROR: number of read items (%u) != number of written items (%u).", g_read_items.size(), g_written_items.size());
        return false;
    }

    if (g_read_items.size() == 0)
    {
        printf("ERROR: number of read items is 0.");
        return false;
    }

    for (std::vector<std::string>::iterator i = g_written_items.begin(); i != g_written_items.end();)
    {
        bool increment_i = true;

        for (std::vector<std::string>::iterator j = g_read_items.begin(); j != g_read_items.end();)
        {
            if (*i == *j)
            {
                g_written_items.erase(i);
                g_read_items.erase(j);

                i = g_written_items.begin();
                increment_i = false;

                break;
            }

            ++j;
        }

        if (increment_i)
            ++i;
    }

    if (g_read_items.size() != g_written_items.size())
    {
        printf("ERROR: there was a corruption during read/write because not all written items were read.\n");

        printf("Leftovers in g_read_items:\n");
        for (size_t i = 0; i < g_read_items.size(); ++i)
            printf("%s ", g_read_items[i].c_str());

        printf("\nLeftovers in g_written_items:\n");
        for (size_t i = 0; i < g_written_items.size(); ++i)
            printf("%s ", g_written_items[i].c_str());
        printf("\n");

        return false;
    }

    if (g_read_items.size() != 0)
    {
        printf("ERROR: read/write problem detected.\n");

        printf("Leftovers in g_read_items:\n");
        for (size_t i = 0; i < g_read_items.size(); ++i)
            printf("%s ", g_read_items[i].c_str());

        printf("\nLeftovers in g_written_items:\n");
        for (size_t i = 0; i < g_written_items.size(); ++i)
            printf("%s ", g_written_items[i].c_str());
        printf("\n");

        return false;
    }

    return true;
}

void run_all_tests()
{
    if (!N_threads_mem_transport_test())
        printf("N_threads_mem_transport_test failed.\n");

    printf("tests finished OK.\n");
}

}};

int _tmain(int argc, _TCHAR* argv[])
{
    spipc::testing::run_all_tests();
	return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include "ItemBase.hpp"

#include <utility>
#include <envire_core/serialization/SerializationRegistration.hpp>

#ifdef CMAKE_ENABLE_PLUGINS
  #include <envire_core/plugin/Plugin.hpp>
#endif

namespace envire { namespace core
{

    /**@class Item
    *
    * Item class
    */
    template<class _ItemData>
    class Item : public ItemBase
    {
    public:
        typedef boost::shared_ptr< Item<_ItemData> > Ptr;
        typedef _ItemData TemplateType;

    protected:

        _ItemData user_data;

    public:

        Item() : ItemBase()
        {
            user_data_ptr = &user_data;
        }

        Item(const Item<_ItemData>& item) :  ItemBase(item), user_data(item.user_data)
        {
            user_data_ptr = &this->user_data;
        }

        Item(Item<_ItemData>&& item) :  ItemBase(item), user_data(std::move(item.user_data))
        {
            user_data_ptr = &this->user_data;
        }

        template <typename... Ts>
        Item(Ts&&... args) : ItemBase(), user_data(std::forward<Ts>(args)...)
        {
            user_data_ptr = &user_data;
        }

        virtual ~Item() {}

        Item<_ItemData>& operator=(const Item<_ItemData>& item)
        {
            ItemBase::operator=(item);
            user_data = item.user_data;
            return *this;
        }

        Item<_ItemData>& operator=(Item<_ItemData>&& item)
        {
            ItemBase::operator=(item);
            user_data = std::move(item.user_data);
            return *this;
        }

        /**@brief setData
        *
        * Sets the user data
        *
        */
        void setData(const _ItemData& data) { this->user_data = data; }
        void setData(_ItemData&& data) { this->user_data = std::move(data); }

        /**@brief getData
        *
        * Returns the user data
        *
        */
        _ItemData& getData() { return this->user_data; }
        const _ItemData& getData() const { return this->user_data; }

        virtual std::type_index getTypeIndex() const
        {
            return std::type_index(typeid(envire::core::Item<_ItemData>));
        }

    private:
        /**Grants access to boost serialization */
        friend class boost::serialization::access;

        /**Serializes the members of this class*/
        template <typename Archive>
        void serialize(Archive &ar, const unsigned int version)
        {
            ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(envire::core::ItemBase);
            ar & BOOST_SERIALIZATION_NVP(user_data);
        }

    };

}}
<commit_msg>fixed missing move when calling parent classes<commit_after>#pragma once

#include "ItemBase.hpp"

#include <utility>
#include <envire_core/serialization/SerializationRegistration.hpp>

#ifdef CMAKE_ENABLE_PLUGINS
  #include <envire_core/plugin/Plugin.hpp>
#endif

namespace envire { namespace core
{

    /**@class Item
    *
    * Item class
    */
    template<class _ItemData>
    class Item : public ItemBase
    {
    public:
        typedef boost::shared_ptr< Item<_ItemData> > Ptr;
        typedef _ItemData TemplateType;

    protected:

        _ItemData user_data;

    public:

        Item() : ItemBase()
        {
            user_data_ptr = &user_data;
        }

        Item(const Item<_ItemData>& item) :  ItemBase(item), user_data(item.user_data)
        {
            user_data_ptr = &this->user_data;
        }

        Item(Item<_ItemData>&& item) :  ItemBase(std::move(item)), user_data(std::move(item.user_data))
        {
            user_data_ptr = &this->user_data;
        }

        template <typename... Ts>
        Item(Ts&&... args) : ItemBase(), user_data(std::forward<Ts>(args)...)
        {
            user_data_ptr = &user_data;
        }

        virtual ~Item() {}

        Item<_ItemData>& operator=(const Item<_ItemData>& item)
        {
            ItemBase::operator=(item);
            user_data = item.user_data;
            return *this;
        }

        Item<_ItemData>& operator=(Item<_ItemData>&& item)
        {
            ItemBase::operator=(std::move(item));
            user_data = std::move(item.user_data);
            return *this;
        }

        /**@brief setData
        *
        * Sets the user data
        *
        */
        void setData(const _ItemData& data) { this->user_data = data; }
        void setData(_ItemData&& data) { this->user_data = std::move(data); }

        /**@brief getData
        *
        * Returns the user data
        *
        */
        _ItemData& getData() { return this->user_data; }
        const _ItemData& getData() const { return this->user_data; }

        virtual std::type_index getTypeIndex() const
        {
            return std::type_index(typeid(envire::core::Item<_ItemData>));
        }

    private:
        /**Grants access to boost serialization */
        friend class boost::serialization::access;

        /**Serializes the members of this class*/
        template <typename Archive>
        void serialize(Archive &ar, const unsigned int version)
        {
            ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(envire::core::ItemBase);
            ar & BOOST_SERIALIZATION_NVP(user_data);
        }

    };

}}
<|endoftext|>


<commit_before>/*
** Anitomy
** Copyright (C) 2014, Eren Okka
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>

#include "keyword.h"
#include "parser.h"
#include "string.h"

namespace anitomy {

Parser::Parser(Elements& data, token_container_t& tokens)
    : data_(&data),
      tokens_(&tokens) {
}

bool Parser::Parse() {
  SearchForKeywords();

  if (parse_options.parse_episode_number)
    SearchForEpisodeNumber();

  SearchForAnimeTitle();

  if (parse_options.parse_release_group &&
      data_->release_group.empty())
    SearchForReleaseGroup();

  if (parse_options.parse_episode_title)
    SearchForEpisodeTitle();

  return !data_->anime_title.empty();
}

////////////////////////////////////////////////////////////////////////////////

void Parser::SearchForKeywords() {
  for (auto token = tokens_->begin(); token != tokens_->end(); ++token) {
    if (token->category != kUnknown)
      continue;

    auto word = token->content;
    TrimString(word);

    // Don't bother if the word is a number that cannot be CRC
    if (word.size() != 8 && IsNumericString(word))
      continue;

    // Checksum
    if (data_->checksum.empty() && IsCrc32(word)) {
      data_->checksum = word;
      token->category = kIdentifier;
      continue;

    // Video resolution
    } else if (data_->resolution.empty() && IsResolution(word)) {
      data_->resolution = word;
      token->category = kIdentifier;
      continue;
    }

    // Performs better than making a case-insensitive Find
    auto keyword = StringToUpperCopy(word);

    // Video info
    if (keyword_manager.Find(kKeywordVideo, keyword)) {
      AppendKeyword(data_->video, word);
      token->category = kIdentifier;

    // Audio info
    } else if (keyword_manager.Find(kKeywordAudio, keyword)) {
      AppendKeyword(data_->audio, word);
      token->category = kIdentifier;

    // Version
    } else if (data_->release_version.empty() &&
               keyword_manager.Find(kKeywordVersion, keyword)) {
      data_->release_version.push_back(word.back());  // number without "v"
      token->category = kIdentifier;

    // Group
    } else if (parse_options.parse_release_group &&
               data_->release_group.empty() &&
               keyword_manager.Find(kKeywordGroup, keyword)) {
      data_->release_group = word;
      token->category = kIdentifier;

    // Extras
    } else if (parse_options.parse_extra_keywords &&
               keyword_manager.Find(kKeywordExtra, keyword)) {
      AppendKeyword(data_->extras, word);
      token->category = kIdentifier;
    } else if (parse_options.parse_extra_keywords &&
               keyword_manager.Find(kKeywordExtraUnsafe, keyword)) {
      AppendKeyword(data_->extras, word);
      if (token->enclosed)
        token->category = kIdentifier;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

void Parser::SearchForEpisodeNumber() {
  // List all tokens that contain a number
  std::vector<size_t> tokens;
  for (size_t i = 0; i < tokens_->size(); i++) {
    auto& token = tokens_->at(i);
    if (token.category != kUnknown)
      continue;  // Skip previously identified tokens
    if (FindNumberInString(token.content) != token.content.npos)
      tokens.push_back(i);
  }
  if (tokens.empty())
    return;

  // If a token matches a known episode pattern, it has to be the episode number
  if (SearchForEpisodePatterns(tokens))
    return;

  // From now on, we're only interested in numeric tokens
  for (auto it = tokens.begin(); it != tokens.end(); ) {
    if (!IsNumericString(tokens_->at(*it).content)) {
      it = tokens.erase(it);
    } else {
      ++it;
    }
  }
  if (tokens.empty())
    return;

  // e.g. "[12]", "(2006)"
  if (SearchForIsolatedNumbers(tokens))
    return;

  // e.g. " - 08"
  if (SearchForSeparatedNumbers(tokens))
    return;

  // Consider using the last number as a last resort
  SearchForLastNumber(tokens);
}

////////////////////////////////////////////////////////////////////////////////

void Parser::SearchForAnimeTitle() {
  // Find the first non-enclosed unknown token
  auto token_begin = std::find_if(tokens_->begin(), tokens_->end(),
      [](const Token& token) {
        return !token.enclosed && token.category == kUnknown;
      });
  if (token_begin == tokens_->end())
    return;

  // Continue until an identifier is found
  auto token_end = std::find_if(token_begin, tokens_->end(),
      [](const Token& token) {
        return token.category == kIdentifier;
      });
  // If within the interval there's an open bracket without its matching pair,
  // move the upper endpoint back to the bracket
  auto last_bracket = token_end;
  bool bracket_open = false;
  for (auto token = token_begin; token != token_end; ++token) {
    if (token->category == kBracket) {
      last_bracket = token;
      bracket_open = !bracket_open;
    }
  }
  if (bracket_open)
    token_end = last_bracket;

  // Build anime title
  BuildElement(data_->anime_title, false, token_begin, token_end);
}

void Parser::SearchForReleaseGroup() {
  auto token_begin = tokens_->begin();
  auto token_end = tokens_->begin();

  do {
    // Find the first enclosed unknown token
    token_begin = std::find_if(token_end, tokens_->end(),
        [](const Token& token) {
          return token.enclosed && token.category == kUnknown;
        });
    if (token_begin == tokens_->end())
      continue;

    // Continue until a bracket or identifier is found
    token_end = std::find_if(token_begin, tokens_->end(),
        [](const Token& token) {
          return token.category == kBracket || token.category == kIdentifier;
        });
    if (token_end->category != kBracket)
      continue;

    // Ignore if it's not the first token in group
    auto previous_token = GetPreviousValidToken(token_begin);
    if (previous_token != tokens_->end() &&
        previous_token->category != kBracket) {
      continue;
    }

    // Build release group, or anime title if it wasn't found earlier
    bool title_not_found = data_->anime_title.empty();
    auto& element = title_not_found ? data_->anime_title : data_->release_group;
    BuildElement(element, !title_not_found, token_begin, token_end);
    return;

  } while (token_begin != tokens_->end());
}

void Parser::SearchForEpisodeTitle() {
  // Find the first non-enclosed unknown token
  auto token_begin = std::find_if(tokens_->begin(), tokens_->end(),
      [](const Token& token) {
        return !token.enclosed && token.category == kUnknown;
      });
  if (token_begin == tokens_->end())
    return;

  // Continue until a bracket or identifier is found
  auto token_end = std::find_if(token_begin, tokens_->end(),
      [](const Token& token) {
        return token.category == kBracket || token.category == kIdentifier;
      });

  // Build episode title
  BuildElement(data_->episode_title, false, token_begin, token_end);
}

}  // namespace anitomy<commit_msg>Continue search if anime title is empty<commit_after>/*
** Anitomy
** Copyright (C) 2014, Eren Okka
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>

#include "keyword.h"
#include "parser.h"
#include "string.h"

namespace anitomy {

Parser::Parser(Elements& data, token_container_t& tokens)
    : data_(&data),
      tokens_(&tokens) {
}

bool Parser::Parse() {
  SearchForKeywords();

  if (parse_options.parse_episode_number)
    SearchForEpisodeNumber();

  SearchForAnimeTitle();

  if (parse_options.parse_release_group &&
      data_->release_group.empty())
    SearchForReleaseGroup();

  if (parse_options.parse_episode_title)
    SearchForEpisodeTitle();

  return !data_->anime_title.empty();
}

////////////////////////////////////////////////////////////////////////////////

void Parser::SearchForKeywords() {
  for (auto token = tokens_->begin(); token != tokens_->end(); ++token) {
    if (token->category != kUnknown)
      continue;

    auto word = token->content;
    TrimString(word);

    // Don't bother if the word is a number that cannot be CRC
    if (word.size() != 8 && IsNumericString(word))
      continue;

    // Checksum
    if (data_->checksum.empty() && IsCrc32(word)) {
      data_->checksum = word;
      token->category = kIdentifier;
      continue;

    // Video resolution
    } else if (data_->resolution.empty() && IsResolution(word)) {
      data_->resolution = word;
      token->category = kIdentifier;
      continue;
    }

    // Performs better than making a case-insensitive Find
    auto keyword = StringToUpperCopy(word);

    // Video info
    if (keyword_manager.Find(kKeywordVideo, keyword)) {
      AppendKeyword(data_->video, word);
      token->category = kIdentifier;

    // Audio info
    } else if (keyword_manager.Find(kKeywordAudio, keyword)) {
      AppendKeyword(data_->audio, word);
      token->category = kIdentifier;

    // Version
    } else if (data_->release_version.empty() &&
               keyword_manager.Find(kKeywordVersion, keyword)) {
      data_->release_version.push_back(word.back());  // number without "v"
      token->category = kIdentifier;

    // Group
    } else if (parse_options.parse_release_group &&
               data_->release_group.empty() &&
               keyword_manager.Find(kKeywordGroup, keyword)) {
      data_->release_group = word;
      token->category = kIdentifier;

    // Extras
    } else if (parse_options.parse_extra_keywords &&
               keyword_manager.Find(kKeywordExtra, keyword)) {
      AppendKeyword(data_->extras, word);
      token->category = kIdentifier;
    } else if (parse_options.parse_extra_keywords &&
               keyword_manager.Find(kKeywordExtraUnsafe, keyword)) {
      AppendKeyword(data_->extras, word);
      if (token->enclosed)
        token->category = kIdentifier;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

void Parser::SearchForEpisodeNumber() {
  // List all tokens that contain a number
  std::vector<size_t> tokens;
  for (size_t i = 0; i < tokens_->size(); i++) {
    auto& token = tokens_->at(i);
    if (token.category != kUnknown)
      continue;  // Skip previously identified tokens
    if (FindNumberInString(token.content) != token.content.npos)
      tokens.push_back(i);
  }
  if (tokens.empty())
    return;

  // If a token matches a known episode pattern, it has to be the episode number
  if (SearchForEpisodePatterns(tokens))
    return;

  // From now on, we're only interested in numeric tokens
  for (auto it = tokens.begin(); it != tokens.end(); ) {
    if (!IsNumericString(tokens_->at(*it).content)) {
      it = tokens.erase(it);
    } else {
      ++it;
    }
  }
  if (tokens.empty())
    return;

  // e.g. "[12]", "(2006)"
  if (SearchForIsolatedNumbers(tokens))
    return;

  // e.g. " - 08"
  if (SearchForSeparatedNumbers(tokens))
    return;

  // Consider using the last number as a last resort
  SearchForLastNumber(tokens);
}

////////////////////////////////////////////////////////////////////////////////

void Parser::SearchForAnimeTitle() {
  // Find the first non-enclosed unknown token
  auto token_begin = std::find_if(tokens_->begin(), tokens_->end(),
      [](const Token& token) {
        return !token.enclosed && token.category == kUnknown;
      });
  if (token_begin == tokens_->end())
    return;

  // Continue until an identifier is found
  auto token_end = std::find_if(token_begin, tokens_->end(),
      [](const Token& token) {
        return token.category == kIdentifier;
      });
  // If within the interval there's an open bracket without its matching pair,
  // move the upper endpoint back to the bracket
  auto last_bracket = token_end;
  bool bracket_open = false;
  for (auto token = token_begin; token != token_end; ++token) {
    if (token->category == kBracket) {
      last_bracket = token;
      bracket_open = !bracket_open;
    }
  }
  if (bracket_open)
    token_end = last_bracket;

  // Build anime title
  BuildElement(data_->anime_title, false, token_begin, token_end);
}

void Parser::SearchForReleaseGroup() {
  auto token_begin = tokens_->begin();
  auto token_end = tokens_->begin();

  do {
    // Find the first enclosed unknown token
    token_begin = std::find_if(token_end, tokens_->end(),
        [](const Token& token) {
          return token.enclosed && token.category == kUnknown;
        });
    if (token_begin == tokens_->end())
      continue;

    // Continue until a bracket or identifier is found
    token_end = std::find_if(token_begin, tokens_->end(),
        [](const Token& token) {
          return token.category == kBracket || token.category == kIdentifier;
        });
    if (token_end->category != kBracket)
      continue;

    // Ignore if it's not the first token in group
    auto previous_token = GetPreviousValidToken(token_begin);
    if (previous_token != tokens_->end() &&
        previous_token->category != kBracket) {
      continue;
    }

    // Build release group, or anime title if it wasn't found earlier
    if (data_->release_group.empty()) {
      BuildElement(data_->release_group, true, token_begin, token_end);
      if (data_->anime_title.empty())
        continue;
    } else if (data_->anime_title.empty()) {
      BuildElement(data_->anime_title, false, token_begin, token_end);
      return;
    }

  } while (token_begin != tokens_->end());
}

void Parser::SearchForEpisodeTitle() {
  // Find the first non-enclosed unknown token
  auto token_begin = std::find_if(tokens_->begin(), tokens_->end(),
      [](const Token& token) {
        return !token.enclosed && token.category == kUnknown;
      });
  if (token_begin == tokens_->end())
    return;

  // Continue until a bracket or identifier is found
  auto token_end = std::find_if(token_begin, tokens_->end(),
      [](const Token& token) {
        return token.category == kBracket || token.category == kIdentifier;
      });

  // Build episode title
  BuildElement(data_->episode_title, false, token_begin, token_end);
}

}  // namespace anitomy<|endoftext|>


<commit_before>//
//  SCSICard.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 22/08/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

// Per the documentation around the GGLabs Apple II SCSI card clone:
//
// A 5380 is mapped to the first eight bytes of slot IO:
//
//	$c0x0	R		current SCSI data register
//	$c0x0	W		output data register
//	$c0x1	R/W		initiator command register
//	$c0x2	R/W		mode select register
//	$c0x3	R/W		target command register
//	$c0x4	R		SCSI bus status
//	$c0x4	W		select enable register
//	$c0x5	R		bus and status register
//	$c0x6	R		input data register
//	$c0x7	R		reset parity and interrupts
//		(i.e. the 5380's standard registers in their usual order)
//
// The remaining eight are used for control functions:
//
//	$c0x8	R/W		PDMA/DACK
//	$c0x9	R		SCSI device ID
//	$c0xa	W		memory bank select register
//	$c0xb	W		reset 5380 SCSI chip
//	$c0xc	-		[unused]
//	$c0xd	W		PDMA mode enable
//	$c0xe	R		read DRQ status through bit 7
//	$c0xf	-		[unused]
//
// Further, per that card's schematic:
//
//	BANK REGISTER: bit 0..3 ROM Addr, 4..6 RAM Addr, 7 RSVD
//
// Which relates to the description:
//
//	The card is also equipped with 16K of ROM and 8K of RAM.
//	These are mapped in the $C800-$CFFF card memory using a banking
//	scheme. The $C0xA bank register selects the which bank of RAM
//	and ROM are mapped. RAM is always at $C800-$CBFF and ROM is
//	at $CC00-$CFFF. The boot code in the first 256 bytes of ROM
//	bank 0 is also mapped in the IOSEL space ($Cn00-$CnFF).
//

#include "SCSICard.hpp"

#include <cstring>

using namespace Apple::II;

ROM::Request SCSICard::rom_request() {
	return ROM::Request(ROM::Name::AppleIISCSICard);
}

// TODO: accept and supply real clock rate.
SCSICard::SCSICard(ROM::Map &map, int clock_rate) :
	scsi_bus_(clock_rate),
	ncr5380_(scsi_bus_, clock_rate),
	storage_(scsi_bus_, 6)
{
	// Grab a copy of the SCSI ROM.
	const auto rom = map.find(ROM::Name::AppleIISCSICard);
	if(rom == map.end()) {
		throw ROMMachine::Error::MissingROMs;
	}
	memcpy(rom_.data(), rom->second.data(), rom_.size());

	// Set up initial banking.
	rom_pointer_ = rom_.data();
	ram_pointer_ = ram_.data();
}

void SCSICard::perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) {
	switch(select) {
		default: break;

		case Select::Device:
			if(is_read) {
				*value = rom_[address & 255];
			}
		break;

		case Select::IO:
			address &= 0xf;
			switch(address) {
				case 0x0:	case 0x1:	case 0x2:	case 0x3:
				case 0x4:	case 0x5:	case 0x6:	case 0x7:
					if(is_read) {
						*value = ncr5380_.read(address);
					} else {
						ncr5380_.write(address, *value);
					}
				break;

				case 0x9:
					if(is_read) {
						*value = uint8_t(ncr5380_.scsi_id());
					}
				break;

				case 0x8:
					// DMA acknowledge.
					if(is_read) {
						*value = ncr5380_.dma_acknowledge();
					} else {
						ncr5380_.dma_acknowledge(*value);
					}
				break;

				case 0xa:
					// RAM and ROM select.
					if(!is_read) {
						const auto rom_base = size_t((*value & 0x0f) << 10);
						const auto ram_base = size_t((*value & 0x70) << 6);

						rom_pointer_ = &rom_[rom_base];
						ram_pointer_ = &ram_[ram_base];
					}
				break;

				case 0xe:
					// DRQ in b7.
					if(is_read) {
						*value = ncr5380_.dma_request() ? 0x80 : 0x00;
					}
				break;

				default:
					printf("Unhandled: %04x %c %02x\n", address, is_read ? 'r' : 'w', *value);
				break;
			}
		break;

		case Select::C8Region:
			if(address & 0x400) {
				if(is_read) {
					*value = rom_pointer_[address & 0x3ff];
				}
			} else {
				if(is_read) {
					*value = ram_pointer_[address & 0x3ff];
				} else {
					ram_pointer_[address & 0x3ff] = *value;
				}
			}
		break;
	}
}

void SCSICard::set_storage_device(const std::shared_ptr<Storage::MassStorage::MassStorageDevice> &device) {
	storage_->set_storage(device);
}
<commit_msg>Add TODO shout-outs.<commit_after>//
//  SCSICard.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 22/08/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

// Per the documentation around the GGLabs Apple II SCSI card clone:
//
// A 5380 is mapped to the first eight bytes of slot IO:
//
//	$c0x0	R		current SCSI data register
//	$c0x0	W		output data register
//	$c0x1	R/W		initiator command register
//	$c0x2	R/W		mode select register
//	$c0x3	R/W		target command register
//	$c0x4	R		SCSI bus status
//	$c0x4	W		select enable register
//	$c0x5	R		bus and status register
//	$c0x6	R		input data register
//	$c0x7	R		reset parity and interrupts
//		(i.e. the 5380's standard registers in their usual order)
//
// The remaining eight are used for control functions:
//
//	$c0x8	R/W		PDMA/DACK
//	$c0x9	R		SCSI device ID
//	$c0xa	W		memory bank select register
//	$c0xb	W		reset 5380 SCSI chip
//	$c0xc	-		[unused]
//	$c0xd	W		PDMA mode enable
//	$c0xe	R		read DRQ status through bit 7
//	$c0xf	-		[unused]
//
// Further, per that card's schematic:
//
//	BANK REGISTER: bit 0..3 ROM Addr, 4..6 RAM Addr, 7 RSVD
//
// Which relates to the description:
//
//	The card is also equipped with 16K of ROM and 8K of RAM.
//	These are mapped in the $C800-$CFFF card memory using a banking
//	scheme. The $C0xA bank register selects the which bank of RAM
//	and ROM are mapped. RAM is always at $C800-$CBFF and ROM is
//	at $CC00-$CFFF. The boot code in the first 256 bytes of ROM
//	bank 0 is also mapped in the IOSEL space ($Cn00-$CnFF).
//

#include "SCSICard.hpp"

#include <cstring>

using namespace Apple::II;

ROM::Request SCSICard::rom_request() {
	return ROM::Request(ROM::Name::AppleIISCSICard);
}

// TODO: accept and supply real clock rate.
SCSICard::SCSICard(ROM::Map &map, int clock_rate) :
	scsi_bus_(clock_rate),
	ncr5380_(scsi_bus_, clock_rate),
	storage_(scsi_bus_, 6)
{
	// Grab a copy of the SCSI ROM.
	const auto rom = map.find(ROM::Name::AppleIISCSICard);
	if(rom == map.end()) {
		throw ROMMachine::Error::MissingROMs;
	}
	memcpy(rom_.data(), rom->second.data(), rom_.size());

	// Set up initial banking.
	rom_pointer_ = rom_.data();
	ram_pointer_ = ram_.data();
}

void SCSICard::perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) {
	switch(select) {
		default: break;

		case Select::Device:
			if(is_read) {
				*value = rom_[address & 255];
			}
		break;

		case Select::IO:
			address &= 0xf;
			switch(address) {
				case 0x0:	case 0x1:	case 0x2:	case 0x3:
				case 0x4:	case 0x5:	case 0x6:	case 0x7:
					if(is_read) {
						*value = ncr5380_.read(address);
					} else {
						ncr5380_.write(address, *value);
					}
				break;

				case 0x9:
					if(is_read) {
						*value = uint8_t(ncr5380_.scsi_id());
					}
				break;

				case 0x8:
					// DMA acknowledge.
					if(is_read) {
						*value = ncr5380_.dma_acknowledge();
					} else {
						ncr5380_.dma_acknowledge(*value);
					}
				break;

				case 0xa:
					// RAM and ROM select.
					if(!is_read) {
						const auto rom_base = size_t((*value & 0x0f) << 10);
						const auto ram_base = size_t((*value & 0x70) << 6);

						rom_pointer_ = &rom_[rom_base];
						ram_pointer_ = &ram_[ram_base];
					}
				break;

				case 0xb:
					if(!is_read) {
						printf("TODO: NCR reset\n");
					}
				break;

				case 0xd:
					if(!is_read) {
						printf("TODO: Enable PDMA\n");
					}
				break;

				case 0xe:
					// DRQ in b7.
					if(is_read) {
						*value = ncr5380_.dma_request() ? 0x80 : 0x00;
					}
				break;

				default:
					printf("Unhandled: %04x %c %02x\n", address, is_read ? 'r' : 'w', *value);
				break;
			}
		break;

		case Select::C8Region:
			if(address & 0x400) {
				if(is_read) {
					*value = rom_pointer_[address & 0x3ff];
				}
			} else {
				if(is_read) {
					*value = ram_pointer_[address & 0x3ff];
				} else {
					ram_pointer_[address & 0x3ff] = *value;
				}
			}
		break;
	}
}

void SCSICard::set_storage_device(const std::shared_ptr<Storage::MassStorage::MassStorageDevice> &device) {
	storage_->set_storage(device);
}
<|endoftext|>


<commit_before><commit_msg>set g_errno to ENOCOLLREC if getRdbBase() returns null.<commit_after><|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                            OpenSim:  Marker.cpp                            *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2016 Stanford University and the Authors                *
 * Author(s): Peter Loan                                                      *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

//=============================================================================
// INCLUDES
//=============================================================================
#include "Marker.h"
#include "Model.h"

//=============================================================================
// STATICS
//=============================================================================
using namespace std;
using namespace OpenSim;
using SimTK::Vec3;

//=============================================================================
// CONSTRUCTOR(S) AND DESTRUCTOR
//=============================================================================
//_____________________________________________________________________________
/**
 * Default constructor.
 */
Marker::Marker() :
Station()
{

}

//_____________________________________________________________________________
/**
 * Destructor.
 */
Marker::~Marker()
{
}

//_____________________________________________________________________________
/**
 * Set the data members of this Marker to their null values.
 */
void Marker::setNull()
{

}
//_____________________________________________________________________________
/**
 * Set the 'frame name' field, which is used when the marker is added to
 * an existing model.
 *
 * @param aName name of frame
 */
void Marker::setFrameName(const string& aName)
{
    const PhysicalFrame* refFrame = dynamic_cast<const PhysicalFrame*>(&getModel().getFrameSet().get(aName));
    if (refFrame)
    {
        setParentFrame(*refFrame);
    }
    else
    {
        string errorMessage = "Markers must be fixed to PhysicalFrames. " + string(aName) + " is not a PhysicalFrame.";
        throw Exception(errorMessage);
    }

}

//_____________________________________________________________________________
/**
 * Get the 'frame name' field, which is used when the marker is added to
 * an existing model.
 *
 * @return aName frame name.
 */
const string& Marker::getFrameName() const
{
    //if (_bodyNameProp.getValueIsDefault())
    //  return NULL;

    return getParentFrame().getName();
}

//_____________________________________________________________________________
/**
 * Change the PhysicalFrame that this marker is attached to. It assumes that the frame is
 * already set, so that extendConnectToModel() needs to be called to update
 * dependent information.
 *
 * @param aFrame Reference to the PhysicalFrame.
 */
void Marker::changeFrame(const OpenSim::PhysicalFrame& aPhysicalFrame)
{

    if (aPhysicalFrame == getParentFrame())
        return;

    setFrameName(aPhysicalFrame.getName());

    extendConnectToModel(updModel());
}

//_____________________________________________________________________________
/**
 * Change the PhysicalFrame that this marker is attached to. It assumes that the body is
 * already set, so that extendConnectToModel() needs to be called to update
 * dependent information.
 *
 * @param s State.
 * @param aBody Reference to the PhysicalFrame.
 */
void Marker::changeFramePreserveLocation(const SimTK::State& s, OpenSim::PhysicalFrame& aPhysicalFrame)
{

    if (aPhysicalFrame == getParentFrame())
        return;

    // Preserve location means to switch bodies without changing
    // the location of the marker in the inertial reference frame.
    Vec3 newLocation;
    newLocation = findLocationInFrame(s, aPhysicalFrame);
    set_location(newLocation);

    setFrameName(aPhysicalFrame.getName());
    extendConnectToModel(aPhysicalFrame.updModel());
}

//=============================================================================
// SCALING
//=============================================================================
//_____________________________________________________________________________
/**
 * Scale the marker.
 *
 * @param aScaleFactors XYZ scale factors.
 */
void Marker::scale(const SimTK::Vec3& aScaleFactors)
{
    upd_location() = get_location().elementwiseMultiply(aScaleFactors);
}

//_____________________________________________________________________________
/**
* Override default implementation by object to intercept and fix the XML node
* underneath the Marker to match current version
*/
/*virtual*/
void Marker::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber)
{

    if (versionNumber < XMLDocument::getLatestVersion()){
        if (versionNumber < 30501) {
            // Parse name of Body under <body>node
            SimTK::Xml::element_iterator bIter = aNode.element_begin("body");
            SimTK::String bName = bIter->getValue();
            // Create nodes for new layout
            SimTK::Xml::Element connectorsElement("connectors");
            SimTK::Xml::Element frameElement("Connector_PhysicalFrame_");
            connectorsElement.insertNodeAfter(connectorsElement.node_end(), frameElement);
            frameElement.setAttributeValue("name", "parent_frame");
            SimTK::Xml::Element connecteeElement("connectee_name");
            connecteeElement.setValue(bName);
            frameElement.insertNodeAfter(frameElement.node_end(), connecteeElement);
            aNode.insertNodeAfter(bIter, connectorsElement);
            aNode.eraseNode(bIter);
        }
    }
    // Call base class now assuming _node has been corrected for current version
    Object::updateFromXMLNode(aNode, versionNumber);
}

void Marker::generateDecorations(bool fixed, const ModelDisplayHints& hints, const SimTK::State& state,
    SimTK::Array_<SimTK::DecorativeGeometry>& appendToThis) const
{
    Super::generateDecorations(fixed, hints, state, appendToThis);
    if (!fixed) return;
    if (hints.get_show_markers()) {
        // @TODO default color, size, shape should be obtained from hints
        const Vec3 pink(1, .6, .8);
        const OpenSim::PhysicalFrame& frame = getParentFrame();
        //const Frame& bf = frame.findBaseFrame();
        //SimTK::Transform bTrans = frame.findTransformInBaseFrame();
        //const Vec3& p_BM = bTrans*get_location();
        appendToThis.push_back(
            SimTK::DecorativeSphere(.005).setBodyId(frame.getMobilizedBodyIndex())
            .setColor(pink).setOpacity(1.0)
            .setTransform(get_location()));
    }
}
<commit_msg>Marker Super::updateFromXMLNode().<commit_after>/* -------------------------------------------------------------------------- *
 *                            OpenSim:  Marker.cpp                            *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2016 Stanford University and the Authors                *
 * Author(s): Peter Loan                                                      *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

//=============================================================================
// INCLUDES
//=============================================================================
#include "Marker.h"
#include "Model.h"

//=============================================================================
// STATICS
//=============================================================================
using namespace std;
using namespace OpenSim;
using SimTK::Vec3;

//=============================================================================
// CONSTRUCTOR(S) AND DESTRUCTOR
//=============================================================================
//_____________________________________________________________________________
/**
 * Default constructor.
 */
Marker::Marker() :
Station()
{

}

//_____________________________________________________________________________
/**
 * Destructor.
 */
Marker::~Marker()
{
}

//_____________________________________________________________________________
/**
 * Set the data members of this Marker to their null values.
 */
void Marker::setNull()
{

}
//_____________________________________________________________________________
/**
 * Set the 'frame name' field, which is used when the marker is added to
 * an existing model.
 *
 * @param aName name of frame
 */
void Marker::setFrameName(const string& aName)
{
    const PhysicalFrame* refFrame = dynamic_cast<const PhysicalFrame*>(&getModel().getFrameSet().get(aName));
    if (refFrame)
    {
        setParentFrame(*refFrame);
    }
    else
    {
        string errorMessage = "Markers must be fixed to PhysicalFrames. " + string(aName) + " is not a PhysicalFrame.";
        throw Exception(errorMessage);
    }

}

//_____________________________________________________________________________
/**
 * Get the 'frame name' field, which is used when the marker is added to
 * an existing model.
 *
 * @return aName frame name.
 */
const string& Marker::getFrameName() const
{
    //if (_bodyNameProp.getValueIsDefault())
    //  return NULL;

    return getParentFrame().getName();
}

//_____________________________________________________________________________
/**
 * Change the PhysicalFrame that this marker is attached to. It assumes that the frame is
 * already set, so that extendConnectToModel() needs to be called to update
 * dependent information.
 *
 * @param aFrame Reference to the PhysicalFrame.
 */
void Marker::changeFrame(const OpenSim::PhysicalFrame& aPhysicalFrame)
{

    if (aPhysicalFrame == getParentFrame())
        return;

    setFrameName(aPhysicalFrame.getName());

    extendConnectToModel(updModel());
}

//_____________________________________________________________________________
/**
 * Change the PhysicalFrame that this marker is attached to. It assumes that the body is
 * already set, so that extendConnectToModel() needs to be called to update
 * dependent information.
 *
 * @param s State.
 * @param aBody Reference to the PhysicalFrame.
 */
void Marker::changeFramePreserveLocation(const SimTK::State& s, OpenSim::PhysicalFrame& aPhysicalFrame)
{

    if (aPhysicalFrame == getParentFrame())
        return;

    // Preserve location means to switch bodies without changing
    // the location of the marker in the inertial reference frame.
    Vec3 newLocation;
    newLocation = findLocationInFrame(s, aPhysicalFrame);
    set_location(newLocation);

    setFrameName(aPhysicalFrame.getName());
    extendConnectToModel(aPhysicalFrame.updModel());
}

//=============================================================================
// SCALING
//=============================================================================
//_____________________________________________________________________________
/**
 * Scale the marker.
 *
 * @param aScaleFactors XYZ scale factors.
 */
void Marker::scale(const SimTK::Vec3& aScaleFactors)
{
    upd_location() = get_location().elementwiseMultiply(aScaleFactors);
}

//_____________________________________________________________________________
/**
* Override default implementation by object to intercept and fix the XML node
* underneath the Marker to match current version
*/
/*virtual*/
void Marker::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber)
{

    if (versionNumber < XMLDocument::getLatestVersion()){
        if (versionNumber < 30501) {
            // Parse name of Body under <body>node
            SimTK::Xml::element_iterator bIter = aNode.element_begin("body");
            SimTK::String bName = bIter->getValue();
            // Create nodes for new layout
            SimTK::Xml::Element connectorsElement("connectors");
            SimTK::Xml::Element frameElement("Connector_PhysicalFrame_");
            connectorsElement.insertNodeAfter(connectorsElement.node_end(), frameElement);
            frameElement.setAttributeValue("name", "parent_frame");
            SimTK::Xml::Element connecteeElement("connectee_name");
            connecteeElement.setValue(bName);
            frameElement.insertNodeAfter(frameElement.node_end(), connecteeElement);
            aNode.insertNodeAfter(bIter, connectorsElement);
            aNode.eraseNode(bIter);
        }
    }
    // Call base class now assuming _node has been corrected for current version
    Super::updateFromXMLNode(aNode, versionNumber);
}

void Marker::generateDecorations(bool fixed, const ModelDisplayHints& hints, const SimTK::State& state,
    SimTK::Array_<SimTK::DecorativeGeometry>& appendToThis) const
{
    Super::generateDecorations(fixed, hints, state, appendToThis);
    if (!fixed) return;
    if (hints.get_show_markers()) {
        // @TODO default color, size, shape should be obtained from hints
        const Vec3 pink(1, .6, .8);
        const OpenSim::PhysicalFrame& frame = getParentFrame();
        //const Frame& bf = frame.findBaseFrame();
        //SimTK::Transform bTrans = frame.findTransformInBaseFrame();
        //const Vec3& p_BM = bTrans*get_location();
        appendToThis.push_back(
            SimTK::DecorativeSphere(.005).setBodyId(frame.getMobilizedBodyIndex())
            .setColor(pink).setOpacity(1.0)
            .setTransform(get_location()));
    }
}
<|endoftext|>


<commit_before>/*!
 * \file c_array.hpp
 * \brief file c_array.hpp
 *
 * Adapted from: c_array.hpp of WRATH:
 *
 * Copyright 2013 by Nomovok Ltd.
 * Contact: info@nomovok.com
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#pragma once

#include <iterator>
#include <fastuidraw/util/util.hpp>
#include <fastuidraw/util/vecN.hpp>

namespace fastuidraw
{

/*!\addtogroup Utility
  @{
 */

/*!
  \brief
  A c_array is a wrapper over a
  C pointer with a size parameter
  to facilitate bounds checking
  and provide an STL-like iterator
  interface.
 */
template<typename T>
class c_array
{
public:

  /*!
    \brief
    STL compliant typedef
  */
  typedef T* pointer;

  /*!
    \brief
    STL compliant typedef; notice that const_pointer
    is type T* and not const T*. This is because
    a c_array is just a HOLDER of a pointer and
    a length and thus the contents of the value
    behind the pointer are independent to the
    value of a c_array.
  */
  typedef T* const_pointer;

  /*!
    \brief
    STL compliant typedef
  */
  typedef T& reference;

  /*!
    \brief
    STL compliant typedef; notice that const_pointer
    is type T& and not const T&. This is because
    a c_array is just a HOLDER of a pointer and
    a length and thus the contents of the value
    behind the pointer are independent to the
    value of a c_array.
  */
  typedef T& const_reference;

  /*!
    \brief
    STL compliant typedef
  */
  typedef T value_type;

  /*!
    \brief
    STL compliant typedef
  */
  typedef size_t size_type;

  /*!
    \brief
    STL compliant typedef
  */
  typedef ptrdiff_t difference_type;

  /*!
    \brief
    iterator typedef to pointer
   */
  typedef pointer iterator;

  /*!
    \brief
    iterator typedef to const_pointer
   */
  typedef const_pointer const_iterator;

  /*!
    \brief
    iterator typedef using std::reverse_iterator.
   */
  typedef std::reverse_iterator<const_iterator>  const_reverse_iterator;

  /*!
    \brief
    iterator typedef using std::reverse_iterator.
   */
  typedef std::reverse_iterator<iterator>        reverse_iterator;

  /*!
    Default ctor, initializing the pointer as nullptr
    with size 0.
   */
  c_array(void):
    m_size(0),
    m_ptr(nullptr)
  {}

  /*!
    Ctor initializing the pointer and size
    \param pptr pointer value
    \param sz size, must be no more than the number of elements that pptr points to.
   */
  template<typename U>
  c_array(U *pptr, size_type sz):
    m_size(sz),
    m_ptr(pptr)
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*!
    Ctor from a vecN, size is the size of the fixed size array
    \param pptr fixed size array that c_array references, must be
                in scope as until c_array is changed
   */
  template<typename U, size_type N>
  c_array(vecN<U, N> &pptr):
    m_size(N),
    m_ptr(pptr.c_ptr())
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*!
    Ctor from a vecN, size is the size of the fixed size array
    \param pptr fixed size array that c_array references, must be
                in scope as until c_array is changed
   */
  template<typename U, size_type N>
  c_array(const vecN<U, N> &pptr):
    m_size(N),
    m_ptr(pptr.c_ptr())
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*
    Ctor from another c_array object.
    \tparam U type U* must be convertible to type T* AND
              the size of U must be the same as the size
              of T
    \param obj value from which to copy
   */
  template<typename U>
  c_array(const c_array<U> &obj):
    m_size(obj.m_size),
    m_ptr(obj.m_ptr)
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*!
    Ctor from a range of pointers.
    \param R R.m_begin will be the pointer and R.m_end - R.m_begin the size.
   */
  c_array(range_type<iterator> R):
    m_size(R.m_end - R.m_begin),
    m_ptr((m_size > 0) ? &*R.m_begin : nullptr)
  {}

  /*!
    Reinterpret style cast for c_array. It is required
    that the sizeof(T)*size() evenly divides sizeof(S).
    \tparam S type to which to be reinterpreted casted
   */
  template<typename S>
  c_array<S>
  reinterpret_pointer(void) const
  {
    S *ptr;
    size_type num_bytes(size() * sizeof(T));
    FASTUIDRAWassert(num_bytes % sizeof(S) == 0);
    ptr = reinterpret_cast<S*>(c_ptr());
    return c_array<S>(ptr, num_bytes / sizeof(S));
  }

  /*!
    Const style cast for c_array. It is required
    that the sizeof(T) is the same as sizeof(S).
    \tparam S type to which to be const casted
   */
  template<typename S>
  c_array<S>
  const_cast_pointer(void) const
  {
    S *ptr;
    FASTUIDRAWstatic_assert(sizeof(S) == sizeof(T));
    ptr = const_cast<S*>(c_ptr());
    return c_array<S>(ptr, m_size);
  }

  /*!
    Pointer of the c_array.
   */
  T*
  c_ptr(void) const
  {
    return m_ptr;
  }

  /*!
    Pointer to the element one past
    the last element of the c_array.
   */
  T*
  end_c_ptr(void) const
  {
    return m_ptr + m_size;
  }

  /*!
    Access named element of c_array, under
    debug build also performs bounds checking.
    \param j index
   */
  T&
  operator[](size_type j) const
  {
    FASTUIDRAWassert(c_ptr() != nullptr);
    FASTUIDRAWassert(j < m_size);
    return c_ptr()[j];
  }

  /*!
    STL compliant function.
   */
  bool
  empty(void) const
  {
    return m_size == 0;
  }

  /*!
    STL compliant function.
   */
  size_type
  size(void) const
  {
    return m_size;
  }

  /*!
    STL compliant function.
   */
  iterator
  begin(void) const
  {
    return iterator(c_ptr());
  }

  /*!
    STL compliant function.
   */
  iterator
  end(void) const
  {
    return iterator(c_ptr() + static_cast<difference_type>(size()));
  }

  /*!
    STL compliant function.
   */
  reverse_iterator
  rbegin(void) const
  {
    return reverse_iterator(end());
  }

  /*!
    STL compliant function.
   */
  reverse_iterator
  rend(void) const
  {
    return reverse_iterator(begin());
  }

  /*!
    Returns the range of the c_array as an
    iterator range.
   */
  range_type<iterator>
  range(void)
  {
    return range_type<iterator>(begin(), end());
  }

  /*!
    Returns the range of the c_array as a
    reverse_iterator range
   */
  range_type<reverse_iterator>
  reverse_range(void)
  {
    return range_type<reverse_iterator>(rbegin(), rend());
  }

  /*!
    Equivalent to
    \code
    operator[](size()-1-I)
    \endcode
    \param I index from the back to retrieve, I=0
             corrseponds to the back of the array.
   */
  T&
  back(size_type I) const
  {
    FASTUIDRAWassert(I < size());
    return (*this)[size() - 1 - I];
  }

  /*!
    STL compliant function.
   */
  T&
  back(void) const
  {
    return (*this)[size() - 1];
  }

  /*!
    STL compliant function.
   */
  T&
  front(void) const
  {
    return (*this)[0];
  }

  /*!
    Returns a sub-array
    \param pos position of returned sub-array to start,
               i.e. returned c_array's c_ptr() will return
               this->c_ptr()+pos. It is an error if pos
               is negative.
    \param length length of sub array to return, note
                  that it is an error if length+pos>size()
                  or if length is negative.
   */
  c_array
  sub_array(size_type pos, size_type length) const
  {
    FASTUIDRAWassert(pos + length <= m_size);
    return c_array(m_ptr + pos, length);
  }

  /*!
    Returns a sub-array, equivalent to
    \code
    sub_array(pos, size() - pos)
    \endcode
    \param pos position of returned sub-array to start,
               i.e. returned c_array's c_ptr() will return
               this->c_ptr() + pos. It is an error is pos
               is negative.
   */
  c_array
  sub_array(size_type pos) const
  {
    FASTUIDRAWassert(pos <= m_size);
    return c_array(m_ptr + pos, m_size - pos);
  }

  /*!
    Returns a sub-array, equivalent to
    \code
    sub_array(R.m_begin, R.m_end - R.m_begin)
    \endcode
    \tparam I type convertible to size_type
    \param R range of returned sub-array
   */
  template<typename I>
  c_array
  sub_array(range_type<I> R) const
  {
    return sub_array(R.m_begin, R.m_end - R.m_begin);
  }

  /*!
    Returns true if and only if the passed
    the c_array references exactly the same
    data as this c_array.
    \param rhs c_array to which to compare
   */
  template<typename U>
  bool
  same_data(const c_array<U> &rhs) const
  {
    return m_size == rhs.m_size
      and m_ptr == rhs.m_ptr;
  }

private:
  template<typename>
  friend class c_array;

  size_type m_size;
  T *m_ptr;
};

/*! @} */

} //namespace
<commit_msg>fastuidraw/util: c_array cleanups<commit_after>/*!
 * \file c_array.hpp
 * \brief file c_array.hpp
 *
 * Adapted from: c_array.hpp of WRATH:
 *
 * Copyright 2013 by Nomovok Ltd.
 * Contact: info@nomovok.com
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#pragma once

#include <iterator>
#include <fastuidraw/util/util.hpp>
#include <fastuidraw/util/vecN.hpp>

namespace fastuidraw
{

/*!\addtogroup Utility
  @{
 */

/*!
  \brief
  A c_array is a wrapper over a
  C pointer with a size parameter
  to facilitate bounds checking
  and provide an STL-like iterator
  interface.
 */
template<typename T>
class c_array
{
public:

  /*!
    \brief
    STL compliant typedef
  */
  typedef T* pointer;

  /*!
    \brief
    STL compliant typedef; notice that const_pointer
    is type T* and not const T*. This is because
    a c_array is just a HOLDER of a pointer and
    a length and thus the contents of the value
    behind the pointer are not part of the value
    of a c_array.
  */
  typedef T* const_pointer;

  /*!
    \brief
    STL compliant typedef
  */
  typedef T& reference;

  /*!
    \brief
    STL compliant typedef; notice that const_pointer
    is type T& and not const T&. This is because
    a c_array is just a HOLDER of a pointer and
    a length and thus the contents of the value
    behind the pointer are not part of the value
    of a c_array.
  */
  typedef T& const_reference;

  /*!
    \brief
    STL compliant typedef
  */
  typedef T value_type;

  /*!
    \brief
    STL compliant typedef
  */
  typedef size_t size_type;

  /*!
    \brief
    STL compliant typedef
  */
  typedef ptrdiff_t difference_type;

  /*!
    \brief
    iterator typedef to pointer
   */
  typedef pointer iterator;

  /*!
    \brief
    iterator typedef to const_pointer
   */
  typedef const_pointer const_iterator;

  /*!
    \brief
    iterator typedef using std::reverse_iterator.
   */
  typedef std::reverse_iterator<const_iterator>  const_reverse_iterator;

  /*!
    \brief
    iterator typedef using std::reverse_iterator.
   */
  typedef std::reverse_iterator<iterator>        reverse_iterator;

  /*!
    Default ctor, initializing the pointer as nullptr
    with size 0.
   */
  c_array(void):
    m_size(0),
    m_ptr(nullptr)
  {}

  /*!
    Ctor initializing the pointer and size
    \param pptr pointer value
    \param sz size, must be no more than the number of elements that pptr points to.
   */
  template<typename U>
  c_array(U *pptr, size_type sz):
    m_size(sz),
    m_ptr(pptr)
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*!
    Ctor from a vecN, size is the size of the fixed size array
    \param pptr fixed size array that c_array references, must be
                in scope as until c_array is changed
   */
  template<typename U, size_type N>
  c_array(vecN<U, N> &pptr):
    m_size(N),
    m_ptr(pptr.c_ptr())
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*!
    Ctor from a vecN, size is the size of the fixed size array
    \param pptr fixed size array that c_array references, must be
                in scope as until c_array is changed
   */
  template<typename U, size_type N>
  c_array(const vecN<U, N> &pptr):
    m_size(N),
    m_ptr(pptr.c_ptr())
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*
    Ctor from another c_array object.
    \tparam U type U* must be convertible to type T* AND
              the size of U must be the same as the size
              of T
    \param obj value from which to copy
   */
  template<typename U>
  c_array(const c_array<U> &obj):
    m_size(obj.m_size),
    m_ptr(obj.m_ptr)
  {
    FASTUIDRAWstatic_assert(sizeof(U) == sizeof(T));
  }

  /*!
    Ctor from a range of pointers.
    \param R R.m_begin will be the pointer and R.m_end - R.m_begin the size.
   */
  c_array(range_type<iterator> R):
    m_size(R.m_end - R.m_begin),
    m_ptr((m_size > 0) ? &*R.m_begin : nullptr)
  {}

  /*!
    Reinterpret style cast for c_array. It is required
    that the sizeof(T)*size() evenly divides sizeof(S).
    \tparam S type to which to be reinterpreted casted
   */
  template<typename S>
  c_array<S>
  reinterpret_pointer(void) const
  {
    S *ptr;
    size_type num_bytes(size() * sizeof(T));
    FASTUIDRAWassert(num_bytes % sizeof(S) == 0);
    ptr = reinterpret_cast<S*>(c_ptr());
    return c_array<S>(ptr, num_bytes / sizeof(S));
  }

  /*!
    Const style cast for c_array. It is required
    that the sizeof(T) is the same as sizeof(S).
    \tparam S type to which to be const casted
   */
  template<typename S>
  c_array<S>
  const_cast_pointer(void) const
  {
    S *ptr;
    FASTUIDRAWstatic_assert(sizeof(S) == sizeof(T));
    ptr = const_cast<S*>(c_ptr());
    return c_array<S>(ptr, m_size);
  }

  /*!
    Pointer of the c_array.
   */
  T*
  c_ptr(void) const
  {
    return m_ptr;
  }

  /*!
    Pointer to the element one past
    the last element of the c_array.
   */
  T*
  end_c_ptr(void) const
  {
    return m_ptr + m_size;
  }

  /*!
    Access named element of c_array, under
    debug build also performs bounds checking.
    \param j index
   */
  reference
  operator[](size_type j) const
  {
    FASTUIDRAWassert(c_ptr() != nullptr);
    FASTUIDRAWassert(j < m_size);
    return c_ptr()[j];
  }

  /*!
    STL compliant function.
   */
  bool
  empty(void) const
  {
    return m_size == 0;
  }

  /*!
    STL compliant function.
   */
  size_type
  size(void) const
  {
    return m_size;
  }

  /*!
    STL compliant function.
   */
  iterator
  begin(void) const
  {
    return iterator(c_ptr());
  }

  /*!
    STL compliant function.
   */
  iterator
  end(void) const
  {
    return iterator(c_ptr() + static_cast<difference_type>(size()));
  }

  /*!
    STL compliant function.
   */
  reverse_iterator
  rbegin(void) const
  {
    return reverse_iterator(end());
  }

  /*!
    STL compliant function.
   */
  reverse_iterator
  rend(void) const
  {
    return reverse_iterator(begin());
  }

  /*!
    Returns the range of the c_array as an
    iterator range.
   */
  range_type<iterator>
  range(void) const
  {
    return range_type<iterator>(begin(), end());
  }

  /*!
    Returns the range of the c_array as a
    reverse_iterator range
   */
  range_type<reverse_iterator>
  reverse_range(void) const
  {
    return range_type<reverse_iterator>(rbegin(), rend());
  }

  /*!
    Equivalent to
    \code
    operator[](size()-1-I)
    \endcode
    \param I index from the back to retrieve, I=0
             corrseponds to the back of the array.
   */
  reference
  back(size_type I) const
  {
    FASTUIDRAWassert(I < size());
    return (*this)[size() - 1 - I];
  }

  /*!
    STL compliant function.
   */
  reference
  back(void) const
  {
    return (*this)[size() - 1];
  }

  /*!
    STL compliant function.
   */
  reference
  front(void) const
  {
    return (*this)[0];
  }

  /*!
    Returns a sub-array
    \param pos position of returned sub-array to start,
               i.e. returned c_array's c_ptr() will return
               this->c_ptr()+pos. It is an error if pos
               is negative.
    \param length length of sub array to return, note
                  that it is an error if length+pos>size()
                  or if length is negative.
   */
  c_array
  sub_array(size_type pos, size_type length) const
  {
    FASTUIDRAWassert(pos + length <= m_size);
    return c_array(m_ptr + pos, length);
  }

  /*!
    Returns a sub-array, equivalent to
    \code
    sub_array(pos, size() - pos)
    \endcode
    \param pos position of returned sub-array to start,
               i.e. returned c_array's c_ptr() will return
               this->c_ptr() + pos. It is an error is pos
               is negative.
   */
  c_array
  sub_array(size_type pos) const
  {
    FASTUIDRAWassert(pos <= m_size);
    return c_array(m_ptr + pos, m_size - pos);
  }

  /*!
    Returns a sub-array, equivalent to
    \code
    sub_array(R.m_begin, R.m_end - R.m_begin)
    \endcode
    \tparam I type convertible to size_type
    \param R range of returned sub-array
   */
  template<typename I>
  c_array
  sub_array(range_type<I> R) const
  {
    return sub_array(R.m_begin, R.m_end - R.m_begin);
  }

  /*!
    Returns true if and only if the passed
    the c_array references exactly the same
    data as this c_array.
    \param rhs c_array to which to compare
   */
  template<typename U>
  bool
  same_data(const c_array<U> &rhs) const
  {
    return m_ptr == rhs.m_ptr
      && m_size * sizeof(T) == rhs.m_size * sizeof(U);
  }

private:
  template<typename>
  friend class c_array;

  size_type m_size;
  T *m_ptr;
};

/*! @} */

} //namespace
<|endoftext|>


<commit_before>/***********************************************************************************
**
** GumpPartyManifest.cpp
**
** Copyright (C) August 2016 Hotride
**
************************************************************************************
*/
//----------------------------------------------------------------------------------
#include "GumpPartyManifest.h"
#include "../Party.h"
#include "../OrionUO.h"
#include "../Network/Packets.h"
#include "../TextEngine/GameConsole.h"
//----------------------------------------------------------------------------------
CGumpPartyManifest::CGumpPartyManifest(uint serial, short x, short y, bool canLoot)
: CGump(GT_PARTY_MANIFEST, serial, x, y), m_CanLoot(canLoot)
{
}
//----------------------------------------------------------------------------------
CGumpPartyManifest::~CGumpPartyManifest()
{
}
//----------------------------------------------------------------------------------
void CGumpPartyManifest::UpdateContent()
{
	Clear();

	Add(new CGUIResizepic(0, 0x0A28, 0, 0, 450, 480));

	CGUIText *text = (CGUIText*)Add(new CGUIText(0x0386, 40, 30));
	text->CreateTextureA(1, "Tell");

	text = (CGUIText*)Add(new CGUIText(0x0386, 80, 30));
	text->CreateTextureA(1, "Kick");

	text = (CGUIText*)Add(new CGUIText(0x0386, 153, 20));
	text->CreateTextureA(2, "Party Manifest");

	bool isLeader = (g_Party.Leader == 0 || g_Party.Leader == g_PlayerSerial);
	bool isMember = (g_Party.Leader != 0 && g_Party.Leader != g_PlayerSerial);

	int yPtr = 48;
	ushort gumpID = 0;

	IFOR(i, 0, 10)
	{
		Add(new CGUIButton(ID_GPM_BUTTON_TELL_MEMBER == i, 0x0FAB, 0x0FAC, 0x0FAD, 40, yPtr + 2));

		if (isLeader)
			Add(new CGUIButton(ID_GPM_BUTTON_KICK_MEMBER == i, 0x0FB1, 0x0FB2, 0x0FB3, 80, yPtr + 2));

		Add(new CGUIGumppic(0x0475, 130, yPtr));

		text = (CGUIText*)Add(new CGUIText(0x0386, 140, yPtr + 1));
		text->CreateTextureA(2, g_Party.Member[i].GetName(i + 1), 250, TS_CENTER);

		yPtr += 25;
	}

	Add(new CGUIButton(ID_GPM_BUTTON_SEND_MESSAGE, 0x0FAB, 0x0FAC, 0x0FAD, 70, 307));

	text = (CGUIText*)Add(new CGUIText(0x0386, 110, 307));
	text->CreateTextureA(2, "Send the party a message");

	if (m_CanLoot)
	{
		Add(new CGUIButton(ID_GPM_BUTTON_LEAVE, 0x0FA2, 0x0FA2, 0x0FA2, 70, 334));

		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 334));
		text->CreateTextureA(2, "Party can loot me");
	}
	else
	{
		Add(new CGUIButton(ID_GPM_BUTTON_LEAVE, 0x0FA9, 0x0FA9, 0x0FA9, 70, 334));

		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 334));
		text->CreateTextureA(2, "Party CANNOT loot me");
	}

	Add(new CGUIButton(ID_GPM_BUTTON_LEAVE, 0x0FAE, 0x0FAF, 0x0FB0, 70, 360));

	if (isMember)
	{
		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 360));
		text->CreateTextureA(2, "Leave the party");
	}
	else
	{
		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 360));
		text->CreateTextureA(2, "Disband the party");
	}

	if (isLeader)
	{
		Add(new CGUIButton(ID_GPM_BUTTON_ADD, 0x0FA8, 0x0FA9, 0x0FAA, 70, 385));

		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 385));
		text->CreateTextureA(2, "Add New Member");
	}

	Add(new CGUIButton(ID_GPM_BUTTON_OKAY, 0x00F9, 0x00F7, 0x00F8, 130, 430));
	Add(new CGUIButton(ID_GPM_BUTTON_CANCEL, 0x00F3, 0x00F2, 0x00F1, 236, 430));
}
//----------------------------------------------------------------------------------
void CGumpPartyManifest::GUMP_BUTTON_EVENT_C
{
	if (serial == ID_GPM_BUTTON_OKAY)
	{
		if (g_Party.Leader != 0 && g_Party.CanLoot != m_CanLoot)
		{
			g_Party.CanLoot = m_CanLoot;

			CPacketPartyChangeLootTypeRequest((uchar)m_CanLoot).Send();
		}

		m_RemoveMark = true;
	}
	else if (serial == ID_GPM_BUTTON_CANCEL)
		m_RemoveMark = true;
	else if (serial == ID_GPM_BUTTON_SEND_MESSAGE)
	{
		if (g_Party.Leader == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "You are not in a party.");
		else
			g_GameConsole.SetText(L"/");
	}
	else if (serial == ID_GPM_BUTTON_LOOT_TYPE)
	{
		m_CanLoot = !m_CanLoot;
		m_WantUpdateContent = true;
	}
	else if (serial == ID_GPM_BUTTON_LEAVE)
	{
		if (g_Party.Leader == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "You are not in a party.");
		else
		{
//???????????????
			IFOR(i, 0, 10)
			{
				if (g_Party.Member[i].Serial != 0)
					CPacketPartyRemoveRequest(g_Party.Member[i].Serial).Send();
			}
//???????????????
		}
	}
	else if (serial == ID_GPM_BUTTON_ADD)
	{
		if (g_Party.Leader == 0 || g_Party.Leader == g_PlayerSerial)
			CPacketPartyInviteRequest().Send();
	}
	else if (serial >= ID_GPM_BUTTON_TELL_MEMBER && serial < ID_GPM_BUTTON_KICK_MEMBER)
	{
		int memberIndex = serial - ID_GPM_BUTTON_TELL_MEMBER;

		if (g_Party.Member[memberIndex].Serial == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "There is no one in that party slot.");
		else
		{
			char buf[10] = {0};
			sprintf_s(buf, "/%i ", memberIndex + 1);
			g_GameConsole.SetText(buf);
		}
	}
	else if (serial >= ID_GPM_BUTTON_KICK_MEMBER)
	{
		int memberIndex = serial - ID_GPM_BUTTON_KICK_MEMBER;

		if (g_Party.Member[memberIndex].Serial == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "There is no one in that party slot.");
		else
			CPacketPartyRemoveRequest(g_Party.Member[memberIndex].Serial).Send();
	}
}
//----------------------------------------------------------------------------------
<commit_msg>Исправлено поведение гампа группы при изменении состояния возможности лута.<commit_after>/***********************************************************************************
**
** GumpPartyManifest.cpp
**
** Copyright (C) August 2016 Hotride
**
************************************************************************************
*/
//----------------------------------------------------------------------------------
#include "GumpPartyManifest.h"
#include "../Party.h"
#include "../OrionUO.h"
#include "../Network/Packets.h"
#include "../TextEngine/GameConsole.h"
//----------------------------------------------------------------------------------
CGumpPartyManifest::CGumpPartyManifest(uint serial, short x, short y, bool canLoot)
: CGump(GT_PARTY_MANIFEST, serial, x, y), m_CanLoot(canLoot)
{
}
//----------------------------------------------------------------------------------
CGumpPartyManifest::~CGumpPartyManifest()
{
}
//----------------------------------------------------------------------------------
void CGumpPartyManifest::UpdateContent()
{
	Clear();

	Add(new CGUIResizepic(0, 0x0A28, 0, 0, 450, 480));

	CGUIText *text = (CGUIText*)Add(new CGUIText(0x0386, 40, 30));
	text->CreateTextureA(1, "Tell");

	text = (CGUIText*)Add(new CGUIText(0x0386, 80, 30));
	text->CreateTextureA(1, "Kick");

	text = (CGUIText*)Add(new CGUIText(0x0386, 153, 20));
	text->CreateTextureA(2, "Party Manifest");

	bool isLeader = (g_Party.Leader == 0 || g_Party.Leader == g_PlayerSerial);
	bool isMember = (g_Party.Leader != 0 && g_Party.Leader != g_PlayerSerial);

	int yPtr = 48;
	ushort gumpID = 0;

	IFOR(i, 0, 10)
	{
		Add(new CGUIButton(ID_GPM_BUTTON_TELL_MEMBER == i, 0x0FAB, 0x0FAC, 0x0FAD, 40, yPtr + 2));

		if (isLeader)
			Add(new CGUIButton(ID_GPM_BUTTON_KICK_MEMBER == i, 0x0FB1, 0x0FB2, 0x0FB3, 80, yPtr + 2));

		Add(new CGUIGumppic(0x0475, 130, yPtr));

		text = (CGUIText*)Add(new CGUIText(0x0386, 140, yPtr + 1));
		text->CreateTextureA(2, g_Party.Member[i].GetName(i + 1), 250, TS_CENTER);

		yPtr += 25;
	}

	Add(new CGUIButton(ID_GPM_BUTTON_SEND_MESSAGE, 0x0FAB, 0x0FAC, 0x0FAD, 70, 307));

	text = (CGUIText*)Add(new CGUIText(0x0386, 110, 307));
	text->CreateTextureA(2, "Send the party a message");

	if (m_CanLoot)
	{
		Add(new CGUIButton(ID_GPM_BUTTON_LOOT_TYPE, 0x0FA2, 0x0FA2, 0x0FA2, 70, 334));

		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 334));
		text->CreateTextureA(2, "Party can loot me");
	}
	else
	{
		Add(new CGUIButton(ID_GPM_BUTTON_LOOT_TYPE, 0x0FA9, 0x0FA9, 0x0FA9, 70, 334));

		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 334));
		text->CreateTextureA(2, "Party CANNOT loot me");
	}

	Add(new CGUIButton(ID_GPM_BUTTON_LEAVE, 0x0FAE, 0x0FAF, 0x0FB0, 70, 360));

	if (isMember)
	{
		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 360));
		text->CreateTextureA(2, "Leave the party");
	}
	else
	{
		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 360));
		text->CreateTextureA(2, "Disband the party");
	}

	if (isLeader)
	{
		Add(new CGUIButton(ID_GPM_BUTTON_ADD, 0x0FA8, 0x0FA9, 0x0FAA, 70, 385));

		text = (CGUIText*)Add(new CGUIText(0x0386, 110, 385));
		text->CreateTextureA(2, "Add New Member");
	}

	Add(new CGUIButton(ID_GPM_BUTTON_OKAY, 0x00F9, 0x00F7, 0x00F8, 130, 430));
	Add(new CGUIButton(ID_GPM_BUTTON_CANCEL, 0x00F3, 0x00F2, 0x00F1, 236, 430));
}
//----------------------------------------------------------------------------------
void CGumpPartyManifest::GUMP_BUTTON_EVENT_C
{
	if (serial == ID_GPM_BUTTON_OKAY)
	{
		if (g_Party.Leader != 0 && g_Party.CanLoot != m_CanLoot)
		{
			g_Party.CanLoot = m_CanLoot;

			CPacketPartyChangeLootTypeRequest((uchar)m_CanLoot).Send();
		}

		m_RemoveMark = true;
	}
	else if (serial == ID_GPM_BUTTON_CANCEL)
		m_RemoveMark = true;
	else if (serial == ID_GPM_BUTTON_SEND_MESSAGE)
	{
		if (g_Party.Leader == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "You are not in a party.");
		else
			g_GameConsole.SetText(L"/");
	}
	else if (serial == ID_GPM_BUTTON_LOOT_TYPE)
	{
		m_CanLoot = !m_CanLoot;
		m_WantUpdateContent = true;
	}
	else if (serial == ID_GPM_BUTTON_LEAVE)
	{
		if (g_Party.Leader == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "You are not in a party.");
		else
		{
//???????????????
			IFOR(i, 0, 10)
			{
				if (g_Party.Member[i].Serial != 0)
					CPacketPartyRemoveRequest(g_Party.Member[i].Serial).Send();
			}
//???????????????
		}
	}
	else if (serial == ID_GPM_BUTTON_ADD)
	{
		if (g_Party.Leader == 0 || g_Party.Leader == g_PlayerSerial)
			CPacketPartyInviteRequest().Send();
	}
	else if (serial >= ID_GPM_BUTTON_TELL_MEMBER && serial < ID_GPM_BUTTON_KICK_MEMBER)
	{
		int memberIndex = serial - ID_GPM_BUTTON_TELL_MEMBER;

		if (g_Party.Member[memberIndex].Serial == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "There is no one in that party slot.");
		else
		{
			char buf[10] = {0};
			sprintf_s(buf, "/%i ", memberIndex + 1);
			g_GameConsole.SetText(buf);
		}
	}
	else if (serial >= ID_GPM_BUTTON_KICK_MEMBER)
	{
		int memberIndex = serial - ID_GPM_BUTTON_KICK_MEMBER;

		if (g_Party.Member[memberIndex].Serial == 0)
			g_Orion.CreateTextMessage(TT_SYSTEM, 0xFFFFFFFF, 3, 0, "There is no one in that party slot.");
		else
			CPacketPartyRemoveRequest(g_Party.Member[memberIndex].Serial).Send();
	}
}
//----------------------------------------------------------------------------------
<|endoftext|>