Commit 17db90d1 authored by Alejandro Homs Puron's avatar Alejandro Homs Puron

Merge branch '93-ordered-ctsaving-header-map' into 'master'

Resolve issue on CtSaving::HeaderMap ordering

Closes #93

See merge request !128
parents 69b1527a f4be1640
Pipeline #12457 passed with stages
in 14 minutes and 12 seconds
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2017
// Copyright (C) : 2009-2019
// European Synchrotron Radiation Facility
// CS40220 38043 Grenoble Cedex 9
// FRANCE
......
###########################################################################
This file is part of LImA, a Library for Image Acquisition
Copyright (C) : 2009-2017
Copyright (C) : 2009-2019
European Synchrotron Radiation Facility
CS40220 38043 Grenoble Cedex 9
FRANCE
......
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2019
// European Synchrotron Radiation Facility
// CS40220 38043 Grenoble Cedex 9
// FRANCE
//
// Contact: lima@esrf.fr
//
// This 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 software 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/>.
//###########################################################################
#ifndef ORDEREDMAP_H
#define ORDEREDMAP_H
#include <vector>
#include <map>
#include <algorithm>
namespace lima {
template <class Key>
class OrderedMapComp
{
public:
using List = std::vector<Key>;
using ListIt = typename List::iterator;
using ListCIt = typename List::const_iterator;
OrderedMapComp(List& l) : m_list(l)
{}
OrderedMapComp& operator =(const OrderedMapComp&)
{
return *this;
}
bool operator()(const Key& a, const Key& b) const
{
const ListCIt f = m_list.begin();
const ListCIt l = m_list.end();
const ListCIt ia = std::find(f, l, a);
const ListCIt ib = std::find(f, l, b);
if ((ia == l) && (ib == l))
return std::less<Key>()(a, b);
return ((ia != l) && ((ib == l) || (ia < ib)));
}
private:
List& m_list;
};
template <class Key, class T>
class OrderedMap
{
public:
using Comp = OrderedMapComp<Key>;
using Map = std::map<Key, T, Comp>;
using value_type = typename Map::value_type;
using iterator = typename Map::iterator;
using const_iterator = typename Map::const_iterator;
OrderedMap() : m_comp(m_list), m_map(m_comp)
{}
OrderedMap(const OrderedMap& other)
: m_list(other.m_list), m_comp(m_list), m_map(m_comp)
{
m_map = other.m_map;
}
OrderedMap(std::initializer_list<value_type> init)
: m_comp(m_list), m_map(m_comp)
{
using InitList = std::initializer_list<value_type>;
typename InitList::const_iterator it, l = init.end();
for (it = init.begin(); it != l; ++it)
insert(*it);
}
iterator begin()
{ return m_map.begin(); }
const_iterator begin() const
{ return m_map.begin(); }
iterator end()
{ return m_map.end(); }
const_iterator end() const
{ return m_map.end(); }
bool empty() const
{ return m_map.empty(); }
T& operator [](const Key& key)
{
_checkKey(key);
return m_map[key];
}
void clear()
{
m_map.clear();
m_list.clear();
}
std::pair<iterator, bool> insert(const value_type& value)
{
_checkKey(value.first);
return m_map.insert(value);
}
template<class InputIt>
void insert(InputIt first, InputIt last)
{
while (first != last)
insert(*first++);
}
iterator find(const Key& key)
{
return m_map.find(key);
}
const_iterator find(const Key& key) const
{
return m_map.find(key);
}
iterator erase(const_iterator pos)
{
Key key = pos->first;
iterator it = m_map.erase(pos);
_eraseKey(key);
return it;
}
// iterator erase(const_iterator first, const_iterator last);
// void swap(OrderedMap& other);
OrderedMap& operator =(const OrderedMap& other)
{
clear();
m_list = other.m_list;
m_map = other.m_map;
return *this;
}
private:
using List = typename Comp::List;
using ListIt = typename Comp::ListIt;
using ListCIt = typename Comp::ListCIt;
void _checkKey(const Key& key)
{
const ListCIt f = m_list.begin();
const ListCIt l = m_list.end();
if (std::find(f, l, key) == l)
m_list.push_back(key);
}
ListIt _eraseKey(const Key& key)
{
const ListCIt f = m_list.begin();
const ListCIt l = m_list.end();
const ListCIt it = std::find(f, l, key);
if (it == l)
throw std::out_of_range("Error erasing OrderedMap key");
return m_list.erase(it);
}
List m_list;
Comp m_comp;
Map m_map;
};
} // namespace lima
#endif // ORDEREDMAP_H
......@@ -20,7 +20,7 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
############################################################################
set(test_src test_membuffer)
set(test_src test_membuffer test_ordered_map)
if (NOT WIN32)
list(APPEND test_src test_regex)
endif()
......
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2011
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
// This 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 software 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 "lima/OrderedMap.h"
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
using namespace lima;
template <class Key>
class test_ordered_map
{
public:
test_ordered_map(string name, std::initializer_list<Key> v)
: vals(v)
{
cout << "Testing OrderedMap<" << name << ", string>" << endl;
exec();
}
void exec()
{
assert(vals.size() >= 4);
using InitIt = typename initializer_list<Key>::const_iterator;
InitIt v = vals.begin();
using Map = OrderedMap<Key, string>;
Map m {{*v++, "First"}, {*v++, "Second"}};
InitIt v3 = v++;
m[*v3] = "Third";
m[*v++] = "Fourth";
using MapCIt = typename Map::const_iterator;
using MapIt = typename Map::iterator;
MapCIt cit;
for (cit = m.begin(); cit != m.end(); ++cit)
cout << "m[" << cit->first << "]="
<< cit->second << endl;
MapIt it1 = m.find(*v3);
MapIt it2 = m.erase(it1);
cout << "erase(m[" << *v3 << "])=<" << it2->first << ","
<< it2->second << ">" << endl;
for (cit = m.begin(); cit != m.end(); ++cit)
cout << "m[" << cit->first << "]="
<< cit->second << endl;
}
private:
initializer_list<Key> vals;
};
int main(int argc, char *argv[])
{
test_ordered_map<int> tint {"int", {2, 1, 0, 4}};
test_ordered_map<string> tstr {"string", {"2", "1", "0", "4"}};
return 0;
}
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2011
// Copyright (C) : 2009-2019
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// CS40220 38043 Grenoble Cedex 9
// FRANCE
//
// Contact: lima@esrf.fr
//
// This 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
......@@ -34,6 +36,7 @@
#include "lima/CtControl.h"
#include "lima/CtConfig.h"
#include "lima/HwSavingCtrlObj.h"
#include "lima/OrderedMap.h"
struct Data;
class TaskEventCallback;
......@@ -118,7 +121,8 @@ namespace lima {
};
typedef std::pair<std::string, std::string> HeaderValue;
typedef std::map<std::string,std::string> HeaderMap;
typedef std::map<std::string, std::string> HeaderMap;
typedef OrderedMap<std::string, std::string> HeaderOrderedMap;
typedef std::map<long,Data> FrameMap;
// --- file parameters
......
......@@ -19,6 +19,9 @@
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//###########################################################################
%MappedType HeaderMap
{
%TypeHeaderCode
......@@ -29,18 +32,23 @@ typedef std::pair<std::string, std::string> HeaderValue;
%End
%ConvertToTypeCode
if (sipIsErr == NULL)
return PyDict_Check(sipPy);
PyObject *key, *value;
SIP_SSIZE_T pos;
if (sipIsErr == NULL)
{
bool aReturnFlag = PyDict_Check(sipPy);
pos = 0;
while(aReturnFlag && PyDict_Next(sipPy, &pos, &key, &value))
aReturnFlag = sipCheckConvertFromPyStr(key) && sipCheckConvertFromPyStr(value);
*sipCppPtr = new HeaderMap();
PyObject *key, *value;
SIP_SSIZE_T pos = 0;
return aReturnFlag;
}
*sipCppPtr = new HeaderMap();
pos = 0;
while (PyDict_Next(sipPy, &pos, &key, &value))
{
if(PyString_Check(key) && PyString_Check(value))
(*sipCppPtr)->insert(HeaderValue(PyString_AS_STRING(key),PyString_AS_STRING(value)));
}
(*sipCppPtr)->insert(HeaderValue(sipConvertFromPyStr(key),sipConvertFromPyStr(value)));
return sipGetState(sipTransferObj);
%End
......@@ -49,9 +57,10 @@ if (sipIsErr == NULL)
PyObject* aReturnDict = PyDict_New();
for(HeaderMap::iterator i = sipCpp->begin();i != sipCpp->end();++i)
{
PyObject *value = PyString_FromString(i->second.c_str());
PyDict_SetItemString(aReturnDict,i->first.c_str(),value);
Py_DECREF(value);
PyObject *key = sipConvertToPyStr(i->first);
PyObject *value = sipConvertToPyStr(i->second);
PyDict_SetItem(aReturnDict,key,value);
Py_DECREF(key); Py_DECREF(value);
}
return aReturnDict;
%End
......@@ -74,22 +83,22 @@ if (sipIsErr == NULL)
{
PyObject *first = PySequence_GetItem(sipPy,0);
PyObject *second = PySequence_GetItem(sipPy,1);
aCheckFlag = (PyString_Check(first) && PyString_Check(second));
aCheckFlag = (sipCheckConvertFromPyStr(first) && sipCheckConvertFromPyStr(second));
Py_DECREF(first);Py_DECREF(second);
}
return aCheckFlag;
}
PyObject *first = PySequence_GetItem(sipPy,0);
PyObject *second = PySequence_GetItem(sipPy,1);
*sipCppPtr = new HeaderValue(PyString_AS_STRING(first),PyString_AS_STRING(second));
*sipCppPtr = new HeaderValue(sipConvertFromPyStr(first),sipConvertFromPyStr(second));
Py_DECREF(first);Py_DECREF(second);
return sipGetState(sipTransferObj);
%End
%ConvertFromTypeCode
PyObject *key = PyString_FromString(sipCpp->first.c_str());
PyObject *value = PyString_FromString(sipCpp->second.c_str());
PyObject *key = sipConvertToPyStr(sipCpp->first);
PyObject *value = sipConvertToPyStr(sipCpp->second);
PyObject* aReturnTuple = PyTuple_Pack(2,key,value);
Py_DECREF(key);Py_DECREF(value);
......
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2011
// Copyright (C) : 2009-2019
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// CS40220 38043 Grenoble Cedex 9
// FRANCE
//
// Contact: lima@esrf.fr
//
// This 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
......@@ -74,7 +76,9 @@ class SaveContainerCbf::Compression : public SinkTaskBase
int _fillHeader(Data &aData,CtSaving::HeaderMap &aHeader,cbf_handle cbf)
{
DEB_MEMBER_FUNCT();
CtSaving::HeaderOrderedMap anOrderedHeader;
cbf_failnez(cbf_new_datablock(cbf, "image_0"));
aData.header.lock();
......@@ -82,9 +86,38 @@ class SaveContainerCbf::Compression : public SinkTaskBase
aHeader.insert(aDataHeader.begin(),aDataHeader.end());
aData.header.unlock();
// Here prepare a Ordered HeaderMap, so sort the header values and insert them
// according to some conventions like Dectris Mini CBF:
// Dectris Mini CBF, look for categories
// 'array_data/header_convention' and 'array_data/header_contents',
// they must be inserted in the header in special order,
// 'convention' BEFORE 'contents'
CtSaving::HeaderMap::iterator it1, it2;
it1 = aHeader.find("array_data/header_convention");
if (it1 != aHeader.end())
{
it2 = aHeader.find("array_data/header_contents");
if (it2 != aHeader.end())
{
anOrderedHeader.insert(*it1);
anOrderedHeader.insert(*it2);
aHeader.erase(it1);
aHeader.erase(it2);
}
}
_fillHeaderFromMap<CtSaving::HeaderMap>(aHeader, cbf);
// Now append ordered header if any
_fillHeaderFromMap<CtSaving::HeaderOrderedMap>(anOrderedHeader, cbf);
return 0;
}
template <class T>
int _fillHeaderFromMap(T& aHeader, cbf_handle cbf)
{
std::string previousCategory;
for(CtSaving::HeaderMap::iterator i = aHeader.begin();
for(typename T::iterator i = aHeader.begin();
i != aHeader.end();++i)
{
size_t found = i->first.find_last_of(LIMA_HEADER_KEY_SEPARATOR);
......@@ -118,7 +151,7 @@ class SaveContainerCbf::Compression : public SinkTaskBase
}
return 0;
}
int _fillData(Data &aData,cbf_handle cbf)
{
DEB_MEMBER_FUNCT();
......
......@@ -562,7 +562,7 @@ long SaveContainerHdf5::_writeFile(void* f,Data &aData,
// write header only once into "parameters" group
// but we should write some keys into measurement, like motor_pos counter_pos (spec)???
if (!aHeader.empty()) {
for (map<string, string>::const_iterator it = aHeader.begin(); it != aHeader.end(); it++) {
for (CtSaving::HeaderMap::const_iterator it = aHeader.begin(); it != aHeader.end(); it++) {
string key = it->first;
string value = it->second;
......
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment