Commit d8e07c2a authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum

[CHANGE] - changed selection/selector interface a bit to match the thread-safe design.

parent 6012ddfb
......@@ -27,6 +27,7 @@
#include "WLogger.h"
#include "exceptions/WOutOfBounds.h"
#include "exceptions/WNameNotUnique.h"
#include "WItemSelector.h"
#include "WItemSelection.h"
......@@ -41,30 +42,10 @@ WItemSelection::~WItemSelection()
// cleanup
}
void WItemSelection::addItem( std::string name, std::string description, const char** icon )
{
ItemListType::WriteTicket w = m_items.getWriteTicket(); // this ensures that invalidation is only triggered when no one else is currently
// reading the selection while we write it is not allowed
invalidateSelectors();
Item* i = new Item; // NOLINT <-- initialize the struct this way is far more comfortable
i->name = name;
i->description = description;
i->icon = icon;
w->get().push_back( i );
}
void WItemSelection::removeItem( std::string name )
{
ItemListType::WriteTicket w = m_items.getWriteTicket(); // this ensures that invalidation is only triggered when no one else is currently
// TODO(ebaum): implement me
}
WItemSelector WItemSelection::getSelectorAll()
{
WItemSelector::IndexList l;
ItemListType::ReadTicket r = m_items.getReadTicket();
ReadTicket r = getReadTicket();
for ( size_t i = 0; i < r->get().size(); ++i )
{
......@@ -76,14 +57,14 @@ WItemSelector WItemSelection::getSelectorAll()
WItemSelector WItemSelection::getSelectorNone()
{
WItemSelector::IndexList l;
ItemListType::ReadTicket r = m_items.getReadTicket();
ReadTicket r = getReadTicket();
return WItemSelector( shared_from_this(), l );
}
WItemSelector WItemSelection::getSelectorFirst()
{
WItemSelector::IndexList l;
ItemListType::ReadTicket r = m_items.getReadTicket();
ReadTicket r = getReadTicket();
if ( r->get().size() >= 1 )
{
......@@ -95,7 +76,7 @@ WItemSelector WItemSelection::getSelectorFirst()
WItemSelector WItemSelection::getSelector( size_t item )
{
WItemSelector::IndexList l;
ItemListType::ReadTicket r = m_items.getReadTicket();
ReadTicket r = getReadTicket();
if ( r->get().size() <= item )
{
......@@ -105,23 +86,8 @@ WItemSelector WItemSelection::getSelector( size_t item )
return WItemSelector( shared_from_this(), l );
}
void WItemSelection::invalidateSelectors()
{
signal_invalidate();
}
boost::signals2::connection WItemSelection::subscribeInvalidationSignal( boost::function< void( void ) > invalidationCallback )
{
return signal_invalidate.connect( invalidationCallback );
}
size_t WItemSelection::size() const
{
return m_items.size();
}
WItemSelection::Item& WItemSelection::at( size_t index ) const
void WItemSelection::addItem( std::string name, std::string description, const char** icon )
{
return *m_items.at( index );
push_back( WItemSelectionItem( name, description, icon ) );
}
......@@ -35,6 +35,7 @@
#include <boost/enable_shared_from_this.hpp>
#include "WSharedSequenceContainer.h"
#include "WItemSelectionItem.h"
#include "WExportCommon.h"
class WItemSelector;
......@@ -44,34 +45,13 @@ class WItemSelector;
* Selectors which are able to select some subset of the item set. This is especially useful in properties where item selection is needed. The
* class is kept very restrictive to keep the interface clean and sleek and to keep the item set consistent among several threads. So please do
* not implement any function that might change the item list, use the provided ones. If the item list changes, existing selectors get invalid
* automatically.
* automatically using the change condition of the inherited WSharedSequenceContainer.
*/
class OWCOMMON_EXPORT WItemSelection: public boost::enable_shared_from_this< WItemSelection >
class OWCOMMON_EXPORT WItemSelection: public boost::enable_shared_from_this< WItemSelection >,
public WSharedSequenceContainer< std::vector< WItemSelectionItem > >
{
friend class WItemSelector; // for proper locking and unlocking
friend class WItemSelector; // for proper locking and unlocking
public:
/**
* For shortening, it is the type of an item.
*/
typedef struct
{
/**
* Name
*/
std::string name;
/**
* Description, can be empty.
*/
std::string description;
/**
* Icon shown in the item selection box. Can be NULL.
*/
const char** icon;
}
Item;
/**
* Default constructor.
*/
......@@ -82,23 +62,6 @@ public:
*/
virtual ~WItemSelection();
/**
* Adds an item to the list of selectable items. If there are any selectors created (using ::getSelectorAll, ::getSelectorFirst,
* ::getSelectorNone or ::getSelector) previously, there are marked as invalid.
*
* \param name the name, it is not required to be unique.
* \param description the description.
* \param icon an icon to show together with this item. Useful to illustrate the selection options.
*/
virtual void addItem( std::string name, std::string description, const char** icon = NULL );
/**
* Removes the items with the given name. If the item does not exist in the list, nothing happens.
*
* \param name the name of the item to remove
*/
virtual void removeItem( std::string name );
/**
* Creates an default selection (all items selected). The selector gets invalid if another item is added.
*
......@@ -130,53 +93,28 @@ public:
virtual WItemSelector getSelector( size_t item );
/**
* Invalidates all selectors currently existing somewhere. This is especially useful with properties when the underlying selection changes
* for a property to ensure nobody can set the property to an old selection.
*/
void invalidateSelectors();
/**
* The number of selectable items.
* Convenience method to create a new item.
*
* \return the number of items.
*/
virtual size_t size() const;
/**
* Gets the item with the given index. This is not the same index as the element has in the corresponding WItemSelector!
* This method is especially useful to iterate the through all items.
*
* \param index the index
* \param name name of the item
* \param description the description, can be empty
* \param icon the icon, can be NULL
*
* \return the item
* \return the Item.
*/
virtual Item& at( size_t index ) const;
static WItemSelectionItem Item( std::string name, std::string description = "", const char** icon = NULL )
{
return WItemSelectionItem( name, description, icon );
}
/**
* Subscribes the specified callback to the invalidation signal getting emitted whenever this selection got invalidated. All selectors using
* this selection subscribe to this signal.
* Convenience method to add a new item.
*
* \param invalidationCallback the callback
* \param name name of the item
* \param description the description, can be empty
* \param icon the icon, can be NULL
*
* \return connection. The subscriber needs to disconnect it.
*/
boost::signals2::connection subscribeInvalidationSignal( boost::function< void( void ) > invalidationCallback );
protected:
/**
* Shortcut for the list type
*/
typedef WSharedSequenceContainer< std::vector< Item* > > ItemListType;
/**
* List of items.
*/
ItemListType m_items;
/**
* This signal is emitted whenever the selection gets invalidated. All created selectors subscribed to it.
*/
boost::signals2::signal< void( void ) > signal_invalidate;
void addItem( std::string name, std::string description = "", const char** icon = NULL );
private:
};
......
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include "WItemSelectionItem.h"
WItemSelectionItem::WItemSelectionItem( std::string name, std::string description, const char** icon ):
m_name( name ),
m_description( description ),
m_icon( icon )
{
// initialize members
}
WItemSelectionItem::~WItemSelectionItem()
{
// cleanup
}
std::string WItemSelectionItem::getName() const
{
return m_name;
}
std::string WItemSelectionItem::getDescription() const
{
return m_description;
}
const char** WItemSelectionItem::getIcon() const
{
return m_icon;
}
bool WItemSelectionItem::operator==( const WItemSelectionItem& other ) const
{
return ( m_name == other.m_name );
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WITEMSELECTIONITEM_H
#define WITEMSELECTIONITEM_H
#include <string>
/**
* Class for keeping a single named item in a WItemSelection.
*/
class WItemSelectionItem
{
public:
/**
* Constructs a new item with the specified values.
*
* \param name Name of item.
* \param description Description, can be empty.
* \param icon Icon, can be NULL.
*/
WItemSelectionItem( std::string name, std::string description = "", const char** icon = NULL );
/**
* Destruction. Does NOT delete the icon!
*/
virtual ~WItemSelectionItem();
/**
* Returns the name of the item.
*
* \return the name
*/
std::string getName() const;
/**
* The description of the item.
*
* \return the description
*/
std::string getDescription() const;
/**
* The icon associated with this item. Can be NULL.
*
* \return the icon, might be NULL.
*/
const char** getIcon() const;
/**
* Compares this and another item using their names only.
*
* \param other the second to compare the this one with
*
* \return true if the names are equal.
*/
bool operator==( const WItemSelectionItem& other ) const;
protected:
/**
* Item name.
*/
std::string m_name;
/**
* Item description.
*/
std::string m_description;
/**
* Item icon.
*/
const char** m_icon;
private:
};
#endif // WITEMSELECTIONITEM_H
......@@ -39,7 +39,7 @@ WItemSelector::WItemSelector( boost::shared_ptr< WItemSelection > selection, Ind
m_valid( true )
{
// initialize members
m_invalidateSignalConnection = m_selection->subscribeInvalidationSignal( boost::bind( &WItemSelector::invalidate, this ) );
m_invalidateSignalConnection = m_selection->getChangeCondition()->subscribeSignal( boost::bind( &WItemSelector::invalidate, this ) );
}
WItemSelector::WItemSelector( const WItemSelector& other ):
......@@ -47,7 +47,7 @@ WItemSelector::WItemSelector( const WItemSelector& other ):
m_selected( other.m_selected ),
m_valid( other.m_valid )
{
m_invalidateSignalConnection = m_selection->subscribeInvalidationSignal( boost::bind( &WItemSelector::invalidate, this ) );
m_invalidateSignalConnection = m_selection->getChangeCondition()->subscribeSignal( boost::bind( &WItemSelector::invalidate, this ) );
}
WItemSelector& WItemSelector::operator=( const WItemSelector & other )
......@@ -58,7 +58,7 @@ WItemSelector& WItemSelector::operator=( const WItemSelector & other )
m_selected = other.m_selected;
m_valid = other.m_valid;
m_invalidateSignalConnection = m_selection->subscribeInvalidationSignal( boost::bind( &WItemSelector::invalidate, this ) );
m_invalidateSignalConnection = m_selection->getChangeCondition()->subscribeSignal( boost::bind( &WItemSelector::invalidate, this ) );
}
// by convention, always return *this
......@@ -97,6 +97,21 @@ WItemSelector WItemSelector::newSelector( const std::string asString ) const
return createSelector( l );
}
WItemSelector WItemSelector::newSelector() const
{
WItemSelector s( *this );
s.m_valid = true;
// iterate selected items to remove items with invalid index
for ( IndexList::iterator i = s.m_selected.begin(); i != s.m_selected.end(); ++i )
{
if ( ( *i ) >= m_selection->size() )
{
s.m_selected.erase( i );
}
}
return s;
}
std::ostream& WItemSelector::operator<<( std::ostream& out ) const
{
for ( WItemSelector::IndexList::const_iterator iter = m_selected.begin(); iter != m_selected.end(); ++iter )
......@@ -117,7 +132,7 @@ std::ostream& operator<<( std::ostream& out, const WItemSelector& other )
bool WItemSelector::operator==( const WItemSelector& other ) const
{
return ( ( m_selection == other.m_selection ) && ( m_selected == other.m_selected ) );
return ( ( m_selection == other.m_selection ) && ( m_selected == other.m_selected ) && ( m_valid == other.m_valid ) );
}
size_t WItemSelector::sizeAll() const
......@@ -130,12 +145,12 @@ size_t WItemSelector::size() const
return m_selected.size();
}
const WItemSelection::Item& WItemSelector::atAll( size_t index ) const
const WItemSelectionItem& WItemSelector::atAll( size_t index ) const
{
return m_selection->at( index );
}
const WItemSelection::Item& WItemSelector::at( size_t index ) const
const WItemSelectionItem& WItemSelector::at( size_t index ) const
{
return m_selection->at( getItemIndexOfSelected( index ) );
}
......@@ -170,7 +185,7 @@ void WItemSelector::lock()
{
// NOTE: it is not needed to check whether lock() has been called earlier. The old lock gets freed in the moment m_lock gets overwritten as
// ReadTickets are reference counted.
m_lock = m_selection->m_items.getReadTicket();
m_lock = m_selection->getReadTicket();
}
void WItemSelector::unlock()
......
......@@ -34,6 +34,7 @@
#include <boost/signals2/signal.hpp>
#include "WItemSelection.h"
#include "WItemSelectionItem.h"
#include "WExportCommon.h"
/**
......@@ -83,6 +84,9 @@ public:
* Creates a new valid instance with the specified items selected. This is especially useful to simply create a new selection if only the old
* selection is known.
*
* \note Please be aware that, in the moment this method returns, another thread can make all selectors invalid again causing the returned
* one to be invalid too. To avoid this, use the newSelector method only if the old has locked the selection using ::lock and ::unlock.
*
* \param selected the selected items (their index in WItemSelection).
*
* \return the new selector instance
......@@ -92,6 +96,9 @@ public:
/**
* Creates a new valid instance with the specified items selected. This can be useful to add a certain index.
*
* \note Please be aware that, in the moment this method returns, another thread can make all selectors invalid again causing the returned
* one to be invalid too. To avoid this, use the newSelector method only if the old has locked the selection using ::lock and ::unlock.
*
* \param selected the selected item (the index in WItemSelection).
*
* \return the new selector instance
......@@ -102,12 +109,26 @@ public:
* Creates a new valid instance with the specified items selected. This is especially useful to simply create a new selection if only the
* string representing it is known. This somehow correlates to the << operator.
*
* \note Please be aware that, in the moment this method returns, another thread can make all selectors invalid again causing the returned
* one to be invalid too. To avoid this, use the newSelector method only if the old has locked the selection using ::lock and ::unlock.
*
* \param asString the selected items
*
* \return the new selector instance
*/
WItemSelector newSelector( const std::string asString ) const;
/**
* Creates a new selector, but basing on this instance as old one. The new selector tries to keep the old selection but makes the internal
* selection list valid with the current underlying selection.
*
* \note Please be aware that, in the moment this method returns, another thread can make all selectors invalid again causing the returned
* one to be invalid too. To avoid this, use the newSelector method only if the old has locked the selection using ::lock and ::unlock.
*
* \return the new (valid) selector.
*/
WItemSelector newSelector() const;
/**
* Compares two selector. They are assumed to be equal if the selected items are equal and if the underlying WItemSelection is the same.
*
......@@ -155,7 +176,7 @@ public:
*
* \return the item
*/
virtual const WItemSelection::Item& atAll( size_t index ) const;
virtual const WItemSelectionItem& atAll( size_t index ) const;
/**
* Gets the selected item with the given index. This is not the same index as the element has in the corresponding WItemSelection!
......@@ -165,7 +186,7 @@ public:
*
* \return the item
*/
virtual const WItemSelection::Item& at( size_t index ) const;
virtual const WItemSelectionItem& at( size_t index ) const;
/**
* Helps to get the index of an selected item in the WItemSelection. This is somehow similar to \ref at, but does not return the item but the
......@@ -246,7 +267,7 @@ private:
/**
* This locks prevents the selection to be modified during selector iteration.
*/
WItemSelection::ItemListType::ReadTicket m_lock;
WItemSelection::ReadTicket m_lock;
};
/**
......
......@@ -52,6 +52,11 @@ public:
*/
typedef typename S::iterator Iterator;
/**
* The type of the elements
*/
typedef typename S::value_type value_type;
/**
* Default constructor.
*/
......@@ -104,7 +109,7 @@ public:
*
* \return reference to element at the specified position
*/
typename S::value_type& operator[]( size_t n );
typename S::value_type& operator[]( size_t n ) ;
/**
* Get item at position n. Uses the [] operator of the underlying container. Please do not use this for iteration as it locks every access.
......@@ -137,13 +142,12 @@ public:
const typename S::value_type& at( size_t n ) const;
/**
* Searches and removes the specified element. If it is not found, nothing happens. It mainly is a comfortable forwarder for std::remove.
* Searches and removes the specified element. If it is not found, nothing happens. It mainly is a comfortable forwarder for std::remove and
* S::erase.
*
* \param element the element to remove
*
* \return the new end iterator.
*/
Iterator erase( const typename S::value_type& element );
void remove( const typename S::value_type& element );
/**
* Erase the element at the specified position. Read your STL reference for more details.
......@@ -164,6 +168,24 @@ public:
*/
Iterator erase( Iterator first, Iterator last );
/**
* Replaces the specified old value by a new one. If the old one does not exist, nothing happens. This is a comfortable forwarder for
* std::replace.
*
* \param oldValue the old value to replace
* \param newValue the new value
*/
void replace( const typename S::value_type& oldValue, const typename S::value_type& newValue );
/**
* Counts the number of occurrences of the specified value inside the container. This is a comfortable forwarder for std::count.
*
* \param value the value to count
*
* \return the number of items found.
*/
size_t count( const value_type& value );
protected:
private:
......@@ -219,7 +241,8 @@ template < typename S >
typename S::value_type& WSharedSequenceContainer< S >::operator[]( size_t n )
{
typename WSharedObject< S >::ReadTicket a = WSharedObject< S >::getReadTicket();
return a->get().operator[]( n );
return const_cast< S& >( a->get() ).operator[]( n ); // read tickets return the handled object const. This is bad here although in most cases
// it is useful and needed.
}
template < typename S >
......@@ -233,7 +256,8 @@ template < typename S >
typename S::value_type& WSharedSequenceContainer< S >::at( size_t n )
{
typename WSharedObject< S >::ReadTicket a = WSharedObject< S >::getReadTicket();
return a->get().at( n );
return const_cast< S& >( a->get() ).at( n ); // read tickets return the handled object const. This is bad here although in most cases it
// is useful and needed.
}
template < typename S >
......@@ -244,11 +268,11 @@ const typename S::value_type& WSharedSequenceContainer< S >::at( size_t n ) cons
}
template < typename S >
typename WSharedSequenceContainer< S >::Iterator WSharedSequenceContainer< S >::erase( const typename S::value_type& element )
void WSharedSequenceContainer< S >::remove( const typename S::value_type& element )
{
// Lock, if "a" looses focus -> look is freed
typename WSharedObject< S >::WriteTicket a = WSharedObject< S >::getWriteTicket();
return std::remove( a->get().begin(), a->get().end(), element );
a->get().erase( std::remove( a->get().begin(), a->get().end(), element ), a->get().end() );
}
template < typename S >
......@@ -269,5 +293,19 @@ typename WSharedSequenceContainer< S >::Iterator WSharedSequenceContainer< S >::
return a->get().erase( first, last );
}
template < typename S >
void WSharedSequenceContainer< S >::replace( const typename S::value_type& oldValue, const typename S::value_type& newValue )
{
typename WSharedObject< S >::WriteTicket a = WSharedObject< S >::getWriteTicket();