void dumpPacket(senf::FileHandle /* ignored */, senf::Scheduler::EventId event)
{
std::string data (sock.read());
- senf::EthernetPacket::ptr packet (
- senf::Packet::create<senf::EthernetPacket>(
- data.begin(), data.end()));
- packet->dump(stream);
- hexdump(packet->last()->begin(),
- packet->last()->end(),
+ senf::EthernetPacket packet (
+ senf::EthernetPacket::create(data));
+ packet.dump(stream);
+ hexdump(packet.last().data().begin(),
+ packet.last().data().end(),
stream);
stream << "\n\n";
}
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
+// compile-command: "scons -u"
// comment-column: 40
// End:
// sock.protocol().promisc("eth0",senf::PacketProtocol::Promiscuous);
while (true) { // forever
- std::string data (sock.read());
- senf::EthernetPacket::ptr packet (
- senf::Packet::create<senf::EthernetPacket>(
- data.begin(), data.end()));
- packet->dump(std::cout);
- hexdump(packet->last()->begin(),
- packet->last()->end());
+ senf::EthernetPacket packet (senf::EthernetPacket::create(
+ senf::EthernetPacket::noinit));
+ sock.read(packet.data(),0);
+ packet.dump(std::cout);
+ hexdump(packet.last().data().begin(),
+ packet.last().data().end());
std::cout << "\n\n";
}
}
private:
void dumpPacket(senf::FileHandle /* ignored */, senf::Scheduler::EventId event)
{
- std::string data (sock.read());
- senf::EthernetPacket::ptr packet (
- senf::Packet::create<senf::EthernetPacket>(
- data.begin(), data.end()));
- packet->dump(std::cout);
- hexdump(packet->last()->begin(),
- packet->last()->end());
+ senf::EthernetPacket packet (
+ senf::EthernetPacket::create(senf::EthernetPacket::noinit));
+ sock.read(packet.data(),0);
+ packet.dump(std::cout);
+ hexdump(packet.last().data().begin(),
+ packet.last().data().end());
std::cout << "\n\n";
}
};
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
+// compile-command: "scons -u"
// comment-column: 40
// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of inline template functions
-
-//#include "DataPacket.ih"
-
-// Custom includes
-
-#define prefix_ inline
-///////////////////////////////cti.p///////////////////////////////////////
-
-template <class Arg>
-prefix_ senf::DataPacket::DataPacket(Arg const & arg)
- : Packet(arg)
-{}
-
-///////////////////////////////cti.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+/** \file
+ \brief DataPacket public header */
+
#ifndef HH_DataPacket_
#define HH_DataPacket_ 1
// Custom includes
+#include "PacketType.hh"
#include "Packet.hh"
+//#include "DataPacket.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
+
+ struct DataPacketType : public PacketTypeBase
+ {};
-
- /** \brief Non-interpreted Packet
-
- A DataPacket is an uninterpreted blob of data. It is terminal
- in the sense, that no further packet header may follow after
- this packet. A DataPacket implements the abstract Packet
- interface and nothing more.
- */
- class DataPacket : public Packet
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<DataPacket>::ptr ptr;
- typedef iterator byte_iterator;
-
- ///////////////////////////////////////////////////////////////////////////
-
- static void init() {}
- static bool check(iterator const & b, iterator const & e) { return true; }
-
- private:
- template <class Arg>
- DataPacket(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
- };
-
-
+ typedef ConcretePacket<DataPacketType> DataPacket;
}
///////////////////////////////hh.e////////////////////////////////////////
//#include "DataPacket.cci"
//#include "DataPacket.ct"
-#include "DataPacket.cti"
+//#include "DataPacket.cti"
#endif
\f
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
// Custom includes
#include <iomanip>
-#include <boost/format.hpp>
+#include <boost/io/ios_state.hpp>
+#include <boost/tokenizer.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
namespace {
- senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::EthVLanPacket>
+ senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::EthVLanPacketType>
registerEthVLanPacket(0x8100);
}
-prefix_ void senf::EthernetPacket::v_nextInterpreter()
- const
+///////////////////////////////////////////////////////////////////////////
+// senf::MACAddress
+
+namespace {
+ senf::PacketParserBase::byte hexToNibble(char c)
+ {
+ if (c<'0')
+ throw senf::MACAddress::SyntaxException();
+ else if (c<='9')
+ return c-'-';
+ else if (c<'A')
+ throw senf::MACAddress::SyntaxException();
+ else if (c<='F')
+ return c-'A'+10;
+ else if (c<'a')
+ throw senf::MACAddress::SyntaxException();
+ else if (c<='f')
+ return c-'a'+10;
+ else
+ throw senf::MACAddress::SyntaxException();
+ }
+
+ template <class Range>
+ senf::PacketParserBase::byte hexToByte(Range const & range)
+ {
+ if (boost::size(range) != 2)
+ throw senf::MACAddress::SyntaxException();
+ typename boost::range_const_iterator<Range>::type i (boost::begin(range));
+ return hexToNibble(i[0])*16+hexToNibble(i[1]);
+ }
+}
+
+prefix_ senf::MACAddress::MACAddress(std::string addr)
{
- /** \todo Add LLC/SNAP support -> only use the registry
- for type() values >=1536, otherwise expect an LLC header */
- registerInterpreter(type(),begin()+bytes(),end());
+ typedef boost::char_separator<char> separator;
+ typedef boost::tokenizer<separator> tokenizer;
+ separator sep (":");
+ tokenizer tok (addr,sep);
+ tokenizer::iterator i (tok.begin());
+ tokenizer::iterator i_end (tok.end());
+ iterator j (begin());
+ iterator j_end (end());
+ for (; i!=i_end && j!=j_end; ++i, ++j)
+ *j = hexToByte(*i);
+ if (i!=i_end || j!=j_end)
+ throw SyntaxException();
}
-namespace {
+///////////////////////////////////////////////////////////////////////////
+// senf::EthernetPacketType
- void dumpmac(std::ostream & os, senf::EthernetPacket::Parse_MAC mac)
+namespace {
+ void dumpmac(std::ostream & os, senf::MACAddress mac)
{
+ boost::io::ios_all_saver ias(os);
for (unsigned i = 0; i < 6; ++i) {
if (i > 0)
os << ':';
<< unsigned(mac[i]);
}
}
-
}
-prefix_ void senf::EthernetPacket::v_dump(std::ostream & os)
- const
+prefix_ void senf::EthernetPacketType::dump(packet p, std::ostream & os)
{
- if (type() <= 1500)
+ if (p->type() <= 1500)
os << "Ethernet 802.3";
- else if (type() >= 0x600)
+ else if (p->type() >= 0x600)
os << "Ethernet II (DIX)";
else
os << "Ethernet 802.3 (bad ethertype >1500 and <1536)";
os << ": \n"
<< " destination : ";
- dumpmac(os,destination());
+ dumpmac(os,p->destination());
os << "\n"
<< " source : ";
- dumpmac(os,source());
+ dumpmac(os,p->source());
os << "\n"
<< " ethertype : " << std::hex << std::setw(4) << std::setfill('0')
- << unsigned(type()) << "\n" << std::dec;
-}
-
-prefix_ void senf::EthernetPacket::v_finalize()
-{}
-
-prefix_ void senf::EthVLanPacket::v_nextInterpreter()
- const
-{
- /** \todo Add LLC/SNAP support (see above) */
- registerInterpreter(type(),begin()+bytes(),end());
+ << unsigned(p->type()) << "\n" << std::dec;
}
-prefix_ void senf::EthVLanPacket::v_finalize()
-{}
-
-prefix_ void senf::EthVLanPacket::v_dump(std::ostream & os)
- const
+prefix_ void senf::EthVLanPacketType::dump(packet p, std::ostream & os)
{
os << "Ethernet 802.1q (VLAN):\n"
- << " priority : " << priority() << "\n"
- << " cfi : " << cfi() << "\n"
- << " vlan-ID : " << vlanId() << "\n"
- << " ethertype : " << boost::format("%04x") % type() << "\n";
+ << " priority : " << p->priority() << "\n"
+ << " cfi : " << p->cfi() << "\n"
+ << " vlan-ID : " << p->vlanId() << "\n"
+ << " ethertype : " << std::hex << std::setw(4) << std::setfill('0')
+ << p->type() << "\n" << std::dec;
}
///////////////////////////////cc.e////////////////////////////////////////
-// Copyright (C) 2007
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
// Stefan Bund <g0dil@berlios.de>
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief IpV6Extensions non-inline template implementation */
+ \brief EthernetPacket non-inline template implementation */
-//#include "IpV6Extensions.ih"
+//#include "EthernetPacket.ih"
// Custom includes
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
-template <class Arg>
-prefix_ senf::IpV6Extension_Fragment::IpV6Extension_Fragment(Arg const & arg)
- : Packet(arg)
-{}
+template <class InputIterator>
+prefix_ senf::MACAddress::MACAddress(InputIterator i)
+{
+ iterator j (begin());
+ iterator j_end (end());
+ for (;j!=j_end;++j,++i)
+ *j = *i;
+}
///////////////////////////////ct.e////////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
+// $id: EthernetPacket.hh 299 2007-07-10 21:23:49Z g0dil $
//
// Copyright (C) 2006
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
#define HH_EthernetPacket_ 1
// Custom includes
-#include "Packets/Packet.hh"
+#include <algorithm>
+#include <boost/array.hpp>
+#include "Packets/PacketType.hh"
#include "Packets/ParseInt.hh"
-#include "Packets/ParseArray.hh"
#include "Packets/PacketRegistry.hh"
+#include "Packets/PacketParser.hh"
//#include "EthernetPacket.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
+ struct MACAddress
+ : boost::array<PacketParserBase::byte,6>
+ {
+ MACAddress(std::string addr);
+ template <class InputIterator>
+ MACAddress(InputIterator i);
+
+ struct SyntaxException : public std::exception
+ { virtual char const * what() const throw() { return "invalid mac address syntax"; } };
+ };
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_Ethernet : public ParserBase<Iterator,IPacket>
+ struct Parse_MAC : public PacketParserBase
{
- template <class I, class P=nil>
- struct rebind { typedef Parse_Ethernet<I,P> parser; };
- typedef Iterator byte_iterator;
+ Parse_MAC(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ typedef MACAddress value_type;
+ static const size_type fixed_bytes = 6u;
- Parse_Ethernet() {}
- Parse_Ethernet(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ value_type value() const { return MACAddress(i()); }
+ void value(value_type const & v) { std::copy(v.begin(), v.end(), i()); }
+ operator value_type () { return value(); }
+ byte & operator[](size_type index) { return *boost::next(i(),index); }
- static unsigned bytes() { return 14; }
+ Parse_MAC const & operator= (value_type const & other) { value(other); return *this; }
+ };
+
+ struct Parse_Ethernet : public PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(Parse_Ethernet);
///////////////////////////////////////////////////////////////////////////
- typedef Parse_Array < 6, Parse_UInt8<>, Iterator > Parse_MAC;
- typedef Parse_UInt16 < Iterator > Parse_Type;
+ typedef Parse_UInt16 Parse_Type;
- Parse_MAC destination() const { return Parse_MAC (this->i() ); }
- Parse_MAC source() const { return Parse_MAC (this->i() + Parse_MAC::size() ); }
- Parse_Type type() const { return Parse_Type (this->i() + 2*Parse_MAC::size() ); }
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((Field)( destination, Parse_MAC ))
+ ((Field)( source, Parse_MAC ))
+ ((Field)( type, Parse_Type )) );
};
struct EtherTypes {
typedef boost::uint16_t key_t;
};
- class EthernetPacket
- : public Packet,
- public Parse_Ethernet<Packet::iterator, EthernetPacket>,
- public PacketRegistryMixin<EtherTypes,EthernetPacket>
+ struct EthernetPacketType
+ : public PacketTypeBase,
+ public PacketTypeMixin<EthernetPacketType, EtherTypes>
{
- using PacketRegistryMixin<EtherTypes,EthernetPacket>::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
+ typedef PacketTypeMixin<EthernetPacketType, EtherTypes> mixin;
+ typedef ConcretePacket<EthernetPacketType> packet;
+ typedef Parse_Ethernet parser;
- typedef ptr_t<EthernetPacket>::ptr ptr;
+ using mixin::nextPacketRange;
+ using mixin::nextPacketType;
+ using mixin::initSize;
+ using mixin::init;
- ///////////////////////////////////////////////////////////////////////////
+ /** \todo Add LLC/SNAP support -> only use the registry
+ for type() values >=1536, otherwise expect an LLC header */
+ static registry_key_t nextPacketKey(packet p)
+ { return p->type(); }
- private:
- template <class Arg>
- EthernetPacket(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
+ static void dump(packet p, std::ostream & os);
};
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_EthVLan : public ParserBase<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_Ethernet<I,P> parser; };
- typedef Iterator byte_iterator;
+ typedef EthernetPacketType::packet EthernetPacket;
- Parse_EthVLan() {}
- Parse_EthVLan(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- static unsigned bytes() { return 4; }
+ struct Parse_EthVLan : public PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(Parse_EthVLan);
///////////////////////////////////////////////////////////////////////////
- typedef Parse_UIntField < 0, 3, Iterator > Parse_Priority;
- typedef Parse_Flag < 3, Iterator > Parse_CFI;
- typedef Parse_UIntField < 4, 16, Iterator > Parse_VLanId;
- typedef Parse_UInt16 < Iterator > Parse_Type;
+ typedef Parse_UIntField < 0, 3 > Parse_Priority;
+ typedef Parse_Flag < 3 > Parse_CFI;
+ typedef Parse_UIntField < 4, 16 > Parse_VLanId;
+ typedef Parse_UInt16 Parse_Type;
- Parse_Priority priority() const { return Parse_Priority(this->i()); }
- Parse_CFI cfi() const { return Parse_CFI(this->i()); }
- Parse_VLanId vlanId() const { return Parse_VLanId(this->i()); }
- Parse_Type type() const { return Parse_Type(this->i()+2); }
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((OverlayField)( priority, Parse_Priority ))
+ ((OverlayField)( cfi, Parse_CFI ))
+ ((Field )( vlanId, Parse_VLanId ))
+ ((Field )( type, Parse_Type )) );
};
- class EthVLanPacket
- : public Packet,
- public Parse_EthVLan<Packet::iterator, EthVLanPacket>,
- public PacketRegistryMixin<EtherTypes, EthVLanPacket>
+ struct EthVLanPacketType
+ : public PacketTypeBase,
+ public PacketTypeMixin<EthVLanPacketType, EtherTypes>
{
- using PacketRegistryMixin<EtherTypes, EthVLanPacket>::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<EthVLanPacket>::ptr ptr;
-
- ///////////////////////////////////////////////////////////////////////////
+ typedef PacketTypeMixin<EthVLanPacketType, EtherTypes> mixin;
+ typedef ConcretePacket<EthVLanPacketType> packet;
+ typedef Parse_EthVLan parser;
- private:
- template <class Arg>
- EthVLanPacket(Arg const & arg);
+ using mixin::nextPacketRange;
+ using mixin::nextPacketType;
+ using mixin::initSize;
+ using mixin::init;
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
+ /** \todo Add LLC/SNAP support -> only use the registry
+ for type() values >=1536, otherwise expect an LLC header */
+ static registry_key_t nextPacketKey(packet p)
+ { return p->type(); }
- friend class Packet;
+ static void dump(packet p, std::ostream & os);
};
+ typedef EthVLanPacketType::packet EthVLanPacket;
}
///////////////////////////////hh.e////////////////////////////////////////
//#include "EthernetPacket.cci"
-//#include "EthernetPacket.ct"
-#include "EthernetPacket.cti"
+#include "EthernetPacket.ct"
+//#include "EthernetPacket.cti"
#endif
\f
// Custom includes
#include "EthernetPacket.hh"
+#include "Packets/DataPacket.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
-
-BOOST_AUTO_UNIT_TEST(ethernetPacket_parser)
-{
- unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // destination MAC
- 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, // source MAC
- 0x10, 0x11 }; // EtherType
- typedef unsigned char * iterator;
- Parse_Ethernet<iterator> p(data);
-
- BOOST_CHECK_EQUAL( p.destination()[2], 0x03 );
- BOOST_CHECK_EQUAL( p.source()[3], 0x0A );
- BOOST_CHECK_EQUAL( p.type(), 0x1011 );
-}
-
BOOST_AUTO_UNIT_TEST(ethernetPacket_packet)
{
- unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // destination MAC
- 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, // source MAC
- 0x10, 0x11 }; // EtherType
- EthernetPacket::ptr p (Packet::create<EthernetPacket>(data, data+sizeof(data)));
+ senf::EthernetPacket::byte data[] =
+ { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // destination MAC
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, // source MAC
+ 0x10, 0x11 }; // EtherType
+ senf::EthernetPacket p (senf::EthernetPacket::create(data));
BOOST_CHECK_EQUAL( p->destination()[3], 0x04 );
BOOST_CHECK_EQUAL( p->source()[0], 0x07 );
BOOST_CHECK_EQUAL( p->type(), 0x1011 );
-
- BOOST_CHECK_THROW( Packet::create<EthernetPacket>(data, data+sizeof(data)-1),
- TruncatedPacketException );
}
BOOST_AUTO_UNIT_TEST(ethernetPacket_chain)
0xab, 0xcd, // EtherType
0xf0, 0xf1, 0xf2, 0xf3, 0xf4 }; // Payload
- EthernetPacket::ptr p (Packet::create<EthernetPacket>(data, data+sizeof(data)));
+ senf::EthernetPacket p (senf::EthernetPacket::create(data));
- BOOST_CHECK( p->next()->is<EthVLanPacket>() );
- EthVLanPacket::ptr v (p->next()->as<EthVLanPacket>());
+ BOOST_REQUIRE( p.next().is<senf::EthVLanPacket>() );
+ senf::EthVLanPacket v (p.next().as<senf::EthVLanPacket>());
BOOST_CHECK_EQUAL( v->priority(), 4u );
BOOST_CHECK( v->cfi() );
BOOST_CHECK_EQUAL( v->vlanId(), 0x234u );
BOOST_CHECK_EQUAL( v->type(), 0xabcd );
- BOOST_CHECK( v->next()->is<DataPacket>() );
- BOOST_CHECK_EQUAL( *v->next()->begin(), 0xf0 );
+ BOOST_CHECK( v.next().is<senf::DataPacket>() );
+ BOOST_CHECK_EQUAL( *v.next().data().begin(), 0xf0 );
}
///////////////////////////////cc.e////////////////////////////////////////
#include "IpV4Packet.hh"
//#include "IpV4Packet.ih"
-#include "EthernetPacket.hh"
// Custom includes
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include "EthernetPacket.hh"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
namespace {
- senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::IpV4Packet>
+ senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::IpV4PacketType>
registerIpV4Packet (0x0800);
- senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV4Packet>
+ senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV4PacketType>
regsiterIpV4Packet2 (4); // IP-in-IP encapsulation
}
-prefix_ void senf::IpV4Packet::v_nextInterpreter()
- const
-{
- registerInterpreter(protocol(),begin()+bytes(),end());
-}
-
-prefix_ void senf::IpV4Packet::v_finalize()
-{}
-
-prefix_ void senf::IpV4Packet::v_dump(std::ostream & os)
- const
+prefix_ void senf::IpV4PacketType::dump(packet p, std::ostream & os)
{
struct in_addr in;
- in.s_addr = htonl(source());
+ in.s_addr = htonl(p->source());
char buffer[128];
std::string src (inet_ntop(AF_INET,&in,buffer,128));
- in.s_addr = htonl(destination());
+ in.s_addr = htonl(p->destination());
std::string dst (inet_ntop(AF_INET,&in,buffer,128));
os << "Internet protocol Version 4:\n"
- << " version : " << version() << "\n"
- << " IHL : " << ihl() << "\n"
- << " TOS : " << unsigned(tos()) << "\n"
- << " length : " << length() << "\n"
- << " identifier : " << identifier() << "\n"
- << " DF : " << df() << "\n"
- << " MF : " << mf() << "\n"
- << " fragment : " << frag() << "\n"
- << " TTL : " << unsigned(ttl()) << "\n"
- << " protocol : " << unsigned(protocol()) << "\n"
- << " CRC : " << std::hex << crc() << std::dec << "\n"
+ << " version : " << p->version() << "\n"
+ << " IHL : " << p->ihl() << "\n"
+ << " TOS : " << unsigned(p->tos()) << "\n"
+ << " length : " << p->length() << "\n"
+ << " identifier : " << p->identifier() << "\n"
+ << " DF : " << p->df() << "\n"
+ << " MF : " << p->mf() << "\n"
+ << " fragment : " << p->frag() << "\n"
+ << " TTL : " << unsigned(p->ttl()) << "\n"
+ << " protocol : " << unsigned(p->protocol()) << "\n"
+ << " CRC : " << std::hex << p->crc() << std::dec << "\n"
<< " source : " << src << "\n"
<< " destination : " << dst << "\n";
}
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of inline template functions
-
-//#include "IpV4Packet.ih"
-
-// Custom includes
-
-#define prefix_ inline
-///////////////////////////////cti.p///////////////////////////////////////
-
-template <class Arg>
-prefix_ senf::IpV4Packet::IpV4Packet(Arg const & arg)
- : Packet(arg)
-{}
-
-///////////////////////////////cti.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
#define HH_IpV4Packet_ 1
// Custom includes
-#include "Packets/Packet.hh"
+#include "Packets/PacketType.hh"
#include "Packets/ParseInt.hh"
-#include "Packets/ParseArray.hh"
#include "Packets/PacketRegistry.hh"
+#include "Packets/PacketParser.hh"
//#include "IpV4Packet.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
-
- template <class Iterator=nil, class IpV4Packet=nil>
- struct Parse_IpV4 : public ParserBase<Iterator,IpV4Packet>
+ struct Parse_IpV4 : public PacketParserBase
{
- template <class I, class P=nil>
- struct rebind { typedef Parse_IpV4<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_IpV4() {}
- Parse_IpV4(Iterator const & i) : ParserBase<Iterator,IpV4Packet>(i) {}
-
- static unsigned bytes() { return 20; }
+ SENF_PACKET_PARSER_NO_INIT(Parse_IpV4);
///////////////////////////////////////////////////////////////////////////
- typedef Parse_UIntField < 0, 4, Iterator > Parse_Version;
- typedef Parse_UIntField < 4, 8, Iterator > Parse_IHL;
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_UInt16 < Iterator > Parse_16bit;
- typedef Parse_Flag < 0, Iterator > Parse_R;
- typedef Parse_Flag < 1, Iterator > Parse_DF;
- typedef Parse_Flag < 2, Iterator > Parse_MF;
- typedef Parse_UIntField < 3, 16, Iterator > Parse_Frag;
- typedef Parse_UInt32 < Iterator > Parse_32bit;
-
- Parse_Version version() const { return Parse_Version (this->i() ); }
- Parse_IHL ihl() const { return Parse_IHL (this->i() ); }
- Parse_8bit tos() const { return Parse_8bit (this->i() + 1 ); }
- Parse_16bit length() const { return Parse_16bit (this->i() + 2 ); }
- Parse_16bit identifier() const { return Parse_16bit (this->i() + 4 ); }
- Parse_R reserved() const { return Parse_R (this->i() + 6 ); }
- Parse_DF df() const { return Parse_DF (this->i() + 6 ); }
- Parse_MF mf() const { return Parse_MF (this->i() + 6 ); }
- Parse_Frag frag() const { return Parse_Frag (this->i() + 6 ); }
- Parse_8bit ttl() const { return Parse_8bit (this->i() + 8 ); }
- Parse_8bit protocol() const { return Parse_8bit (this->i() + 9 ); }
- Parse_16bit crc() const { return Parse_16bit (this->i() + 10 ); }
- Parse_32bit source() const { return Parse_32bit (this->i() + 12 ); }
- Parse_32bit destination() const { return Parse_32bit (this->i() + 16 ); }
+ typedef Parse_UIntField < 0, 4 > Parse_Version;
+ typedef Parse_UIntField < 4, 8 > Parse_IHL;
+ typedef Parse_UInt8 Parse_8bit;
+ typedef Parse_UInt16 Parse_16bit;
+ typedef Parse_Flag < 0 > Parse_R;
+ typedef Parse_Flag < 1 > Parse_DF;
+ typedef Parse_Flag < 2 > Parse_MF;
+ typedef Parse_UIntField < 3, 16 > Parse_Frag;
+ typedef Parse_UInt32 Parse_32bit;
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((OverlayField)( version, Parse_Version ))
+ ((Field )( ihl, Parse_IHL ))
+ ((Field )( tos, Parse_8bit ))
+ ((Field )( length, Parse_16bit ))
+ ((Field )( identifier, Parse_16bit ))
+ ((OverlayField)( reserved, Parse_R ))
+ ((OverlayField)( df, Parse_DF ))
+ ((OverlayField)( mf, Parse_MF ))
+ ((Field )( frag, Parse_Frag ))
+ ((Field )( ttl, Parse_8bit ))
+ ((Field )( protocol, Parse_8bit ))
+ ((Field )( crc, Parse_16bit ))
+ ((Field )( source, Parse_32bit ))
+ ((Field )( destination, Parse_32bit )) );
+
+ void init() {
+ version() = 4;
+ }
};
struct IpTypes {
typedef boost::uint16_t key_t;
};
- class IpV4Packet
- : public Packet,
- public Parse_IpV4<Packet::iterator,IpV4Packet>,
- public PacketRegistryMixin<IpTypes,IpV4Packet>
+ struct IpV4PacketType
+ : public PacketTypeBase,
+ public PacketTypeMixin<IpV4PacketType, IpTypes>
{
- using PacketRegistryMixin<IpTypes,IpV4Packet>::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
+ typedef PacketTypeMixin<IpV4PacketType, IpTypes> mixin;
+ typedef ConcretePacket<IpV4PacketType> packet;
+ typedef Parse_IpV4 parser;
- typedef ptr_t<IpV4Packet>::ptr ptr;
+ using mixin::nextPacketRange;
+ using mixin::nextPacketType;
+ using mixin::initSize;
+ using mixin::init;
- ///////////////////////////////////////////////////////////////////////////
-
- private:
- template <class Arg>
- IpV4Packet(Arg const & arg);
+ static registry_key_t nextPacketKey(packet p)
+ { return p->protocol(); }
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
+ static void dump(packet p, std::ostream & os);
};
+
+ typedef IpV4PacketType::packet IpV4Packet;
+
}
///////////////////////////////hh.e////////////////////////////////////////
//#include IpV4Packet.cci"
//#include "IpV4Packet.ct"
-#include "IpV4Packet.cti"
+//#include "IpV4Packet.cti"
#endif
\f
using namespace senf;
-BOOST_AUTO_UNIT_TEST(ipV4Packet_parser)
-{
- unsigned char data[] = { 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0A, 0x0B, 0x0C,
- 0x11, 0x12, 0x13, 0x14,
- 0x15, 0x16, 0x17, 0x18
- };
-
- typedef unsigned char * iterator;
- Parse_IpV4<iterator> p(data);
-
- BOOST_CHECK_EQUAL( p.version(), 0x00u );
- BOOST_CHECK_EQUAL( p.ihl(), 0x01u );
- // the static_cast is to silence gcc-3.3
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.tos()), 0x02u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.length()), 0x0304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.identifier()), 0x0506u );
- BOOST_CHECK_EQUAL( p.reserved(), 0 );
- BOOST_CHECK_EQUAL( p.df(), 0 );
- BOOST_CHECK_EQUAL( p.mf(), 0 );
- BOOST_CHECK_EQUAL( p.frag(), 0x0708u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.ttl()), 0x09u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.protocol()), 0x0Au );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.crc()), 0x0B0Cu );
- BOOST_CHECK_EQUAL( p.source(), 0x11121314u );
- BOOST_CHECK_EQUAL( p.destination(), 0x15161718u );
-
-}
-
-
BOOST_AUTO_UNIT_TEST(ipV4Packet_packet)
{
0x15, 0x16, 0x17, 0x18
};
- IpV4Packet::ptr p (Packet::create<IpV4Packet>(data, data+sizeof(data)));
+ senf::IpV4Packet p (senf::IpV4Packet::create(data));
BOOST_CHECK_EQUAL( p->version(), 0x00u );
BOOST_CHECK_EQUAL( p->ihl(), 0x01u );
- // the static_cast is to silence gcc-3.3
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->tos()), 0x02u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->length()), 0x0304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->identifier()), 0x0506u );
+ BOOST_CHECK_EQUAL( p->tos(), 0x02u );
+ BOOST_CHECK_EQUAL( p->length(), 0x0304u );
+ BOOST_CHECK_EQUAL( p->identifier(), 0x0506u );
BOOST_CHECK_EQUAL( p->reserved(), 0 );
BOOST_CHECK_EQUAL( p->df(), 0 );
BOOST_CHECK_EQUAL( p->mf(), 0 );
BOOST_CHECK_EQUAL( p->frag(), 0x0708u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->ttl()), 0x09u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->protocol()), 0x0Au );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->crc()), 0x0B0Cu );
+ BOOST_CHECK_EQUAL( p->ttl(), 0x09u );
+ BOOST_CHECK_EQUAL( p->protocol(), 0x0Au );
+ BOOST_CHECK_EQUAL( p->crc(), 0x0B0Cu );
BOOST_CHECK_EQUAL( p->source(), 0x11121314u );
BOOST_CHECK_EQUAL( p->destination(), 0x15161718u );
-
-
}
-
-
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
///////////////////////////////cc.p////////////////////////////////////////
namespace {
- senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV6Extension_Fragment>
- registerIpV6Extension_Fragment (44);
+ senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV6ExtensionType_Fragment>
+ registerIpV6ExtensionType_Fragment (44);
}
-prefix_ void senf::IpV6Extension_Fragment::v_nextInterpreter()
- const
-{
- registerInterpreter(nextHeader(),begin()+bytes(),end());
-}
-
-prefix_ void senf::IpV6Extension_Fragment::v_finalize()
-{}
-
-prefix_ void senf::IpV6Extension_Fragment::v_dump(std::ostream & os)
- const
+prefix_ void senf::IpV6ExtensionType_Fragment::dump(packet p, std::ostream & os)
{
os << "Internet protocol Version 6 fragment extension:\n"
- << " next header : " << unsigned(nextHeader()) << "\n"
- << " fragment offset: " << std::hex << unsigned(fragmentOffset()) << "\n"
- << " more fragments : " << (moreFragments()?"yes":"no") << "\n"
- << " id : " << std::hex << unsigned(id()) << "\n";
+ << " next header : " << unsigned(p->nextHeader()) << "\n"
+ << " fragment offset: " << std::hex << unsigned(p->fragmentOffset()) << "\n"
+ << " more fragments : " << (p->moreFragments()?"yes":"no") << "\n"
+ << " id : " << std::hex << unsigned(p->id()) << "\n";
}
///////////////////////////////cc.e////////////////////////////////////////
namespace senf {
// See RFC2460
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_IpV6Extension_Fragment
- : public ParserBase<Iterator,IPacket>
+ struct Parse_IpV6Extension_Fragment : public PacketParserBase
{
- template <class I, class P=nil>
- struct rebind { typedef Parse_IpV6Extension_Fragment<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_IpV6Extension_Fragment() {}
- Parse_IpV6Extension_Fragment(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- static unsigned bytes() { return 8; }
+ SENF_PACKET_PARSER_INIT(Parse_IpV6Extension_Fragment);
///////////////////////////////////////////////////////////////////////////
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_UIntField < 0, 13, Iterator > Parse_Offset;
- typedef Parse_UIntField < 13, 15, Iterator > Parse_Reserved;
- typedef Parse_Flag < 15, Iterator > Parse_More;
- typedef Parse_UInt32 < Iterator > Parse_32bit;
-
- Parse_8bit nextHeader() const { return Parse_8bit (this->i() ); }
- Parse_8bit reserved1() const { return Parse_8bit (this->i() + 1 ); }
- Parse_Offset fragmentOffset() const { return Parse_Offset (this->i() + 2 ); }
- Parse_Reserved reserved2() const { return Parse_Reserved (this->i() + 2 ); }
- Parse_More moreFragments() const { return Parse_More (this->i() + 2 ); }
- Parse_32bit id() const { return Parse_32bit (this->i() + 4 ); }
+ typedef Parse_UInt8 Parse_8bit;
+ typedef Parse_UIntField < 0, 13 > Parse_Offset;
+ typedef Parse_UIntField < 13, 15 > Parse_Reserved;
+ typedef Parse_Flag < 15 > Parse_More;
+ typedef Parse_UInt32 Parse_32bit;
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((Field )( nextHeader , Parse_8bit ))
+ ((Field )( reserved1 , Parse_8bit ))
+ ((OverlayField)( fragmentOffset , Parse_Offset ))
+ ((OverlayField)( reserved2 , Parse_Reserved ))
+ ((Field )( moreFragments , Parse_More ))
+ ((Field )( id , Parse_32bit )) );
};
- class IpV6Extension_Fragment
- : public Packet,
- public Parse_IpV6Extension_Fragment<Packet::iterator, IpV6Extension_Fragment>,
- public PacketRegistryMixin<IpTypes, IpV6Extension_Fragment>
+ struct IpV6ExtensionType_Fragment
+ : public PacketTypeBase,
+ public PacketTypeMixin<IpV6ExtensionType_Fragment, IpTypes>
{
- using PacketRegistryMixin<IpTypes,IpV6Extension_Fragment>::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<IpV6Extension_Fragment>::ptr ptr;
-
- ///////////////////////////////////////////////////////////////////////////
-
- private:
- template <class Arg>
- IpV6Extension_Fragment(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
+ typedef PacketTypeMixin<IpV6ExtensionType_Fragment, IpTypes> mixin;
+ typedef ConcretePacket<IpV6ExtensionType_Fragment> packet;
+ typedef Parse_IpV6Extension_Fragment parser;
+
+ using mixin::nextPacketRange;
+ using mixin::nextPacketType;
+ using mixin::initSize;
+ using mixin::init;
+
+ static registry_key_t nextPacketKey(packet p)
+ { return p->nextHeader(); }
+
+ static void dump(packet p, std::ostream & os);
};
+
+ typedef IpV6ExtensionType_Fragment::packet IpV6Extension_Fragment;
}
///////////////////////////////hh.e////////////////////////////////////////
//#include "IpV6Extensions.cci"
-#include "IpV6Extensions.ct"
+//#include "IpV6Extensions.ct"
//#include "IpV6Extensions.cti"
#endif
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
-
-BOOST_AUTO_UNIT_TEST(ipv6Extension_Fragment_parser)
-{
- unsigned char data[] = { 59, 0, 0x10, 0x20,
- 0x01, 0x02, 0x03, 0x04 };
-
- typedef unsigned char * iterator;
- Parse_IpV6Extension_Fragment<iterator> p (data);
-
- BOOST_CHECK_EQUAL( unsigned(p.nextHeader()), 59u );
- BOOST_CHECK_EQUAL( unsigned(p.fragmentOffset()), 0x1020u >> 3 );
- BOOST_CHECK ( ! p.moreFragments() );
- BOOST_CHECK_EQUAL( unsigned(p.id()), 0x01020304u );
-}
-
BOOST_AUTO_UNIT_TEST(ipv6Extension_Fragment_packet)
{
// Just for the fun of it, we test a nice chain: A fragment of a fragmented UDP packet
0x11, 0x12, 0x13, 0x14
};
- IpV6Packet::ptr p (Packet::create<IpV6Packet>(data, data + sizeof(data)));
+ senf::IpV6Packet p (senf::IpV6Packet::create(data));
BOOST_CHECK_EQUAL( p->version(), 6u );
BOOST_CHECK_EQUAL( p->length(), 20u );
BOOST_CHECK_EQUAL( p->nextHeader(), 44u );
- BOOST_CHECK_EQUAL( INet6Address(p->source().range()), "2001::1" );
- BOOST_CHECK_EQUAL( INet6Address(p->destination().range()), "2001::2" );
- BOOST_CHECK( p->next()->is<IpV6Extension_Fragment>() );
+ BOOST_CHECK_EQUAL( senf::INet6Address(p->source()), "2001::1" );
+ BOOST_CHECK_EQUAL( senf::INet6Address(p->destination()), "2001::2" );
+ BOOST_CHECK( p.next().is<senf::IpV6Extension_Fragment>() );
- IpV6Extension_Fragment::ptr f (p->next()->as<IpV6Extension_Fragment>());
+ senf::IpV6Extension_Fragment f (p.next().as<senf::IpV6Extension_Fragment>());
BOOST_CHECK_EQUAL( f->nextHeader(), 17u );
BOOST_CHECK_EQUAL( f->fragmentOffset(), 160u );
BOOST_CHECK_EQUAL( f->id(), 0x01020304u );
- BOOST_CHECK( f->next()->is<UDPPacket>() );
+ BOOST_CHECK( f.next().is<senf::UDPPacket>() );
- UDPPacket::ptr u (f->next()->as<UDPPacket>());
+ senf::UDPPacket u (f.next().as<senf::UDPPacket>());
BOOST_CHECK_EQUAL( u->source(), 0x1000u );
BOOST_CHECK_EQUAL( u->destination(), 0x2000u );
BOOST_CHECK_EQUAL( u->length(), 12u );
- BOOST_CHECK( u->next()->is<DataPacket>() );
+ BOOST_CHECK( u.next().is<senf::DataPacket>() );
- Packet::iterator i (u->next()->begin());
- BOOST_CHECK_EQUAL( Parse_UInt32<Packet::iterator>(i).value(), 0x11121314u );
+ senf::DataPacket d (u.next().as<senf::DataPacket>());
+ senf::Packet::iterator i (u.next().data().begin());
+ BOOST_CHECK_EQUAL( d.size(), 4u );
+ BOOST_CHECK_EQUAL( d.data()[0], 0x11 );
}
///////////////////////////////cc.e////////////////////////////////////////
// Custom includes
#include "EthernetPacket.hh"
+#include "Packets/DataPacket.hh"
#include "Socket/INetAddressing.hh"
//#include "IpV6Packet.mpp"
///////////////////////////////cc.p////////////////////////////////////////
namespace {
- senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::IpV6Packet>
+ senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::IpV6PacketType>
registerIpV6Packet (0x86dd);
- senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV6Packet>
+ senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV6PacketType>
registerIpV6Packet2 (41); // IP6-in-IP(6) encapsulation
- senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::DataPacket>
+ senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::DataPacketType>
registerNoNextHeader (59);
}
-prefix_ void senf::IpV6Packet::v_nextInterpreter()
- const
-{
- registerInterpreter(nextHeader(),begin()+bytes(),end());
-}
-
-prefix_ void senf::IpV6Packet::v_finalize()
-{}
-
-prefix_ void senf::IpV6Packet::v_dump(std::ostream & os)
- const
+prefix_ void senf::IpV6PacketType::dump(packet p, std::ostream & os)
{
os << "Internet protocol Version 6:\n"
- << " version : " << unsigned(version()) << "\n"
- << " traffic class : " << std::hex << unsigned(trafficClass()) << "\n"
- << " flow label : " << std::hex << unsigned(flowLabel()) << "\n"
- << " length : " << std::dec << unsigned(length()) << "\n"
- << " next header : " << unsigned(nextHeader()) << "\n"
- << " hop limit : " << unsigned(hopLimit()) << "\n"
- << " source : " << INet6Address(source().range()) << "\n"
- << " destination : " << INet6Address(destination().range()) << "\n";
+ << " version : " << unsigned(p->version()) << "\n"
+ << " traffic class : " << std::hex << unsigned(p->trafficClass()) << "\n"
+ << " flow label : " << std::hex << unsigned(p->flowLabel()) << "\n"
+ << " length : " << std::dec << unsigned(p->length()) << "\n"
+ << " next header : " << unsigned(p->nextHeader()) << "\n"
+ << " hop limit : " << unsigned(p->hopLimit()) << "\n"
+ << " source : " << INet6Address(p->source()) << "\n"
+ << " destination : " << INet6Address(p->destination()) << "\n";
}
///////////////////////////////cc.e////////////////////////////////////////
#define HH_IpV6Packet_ 1
// Custom includes
-#include "Packets/Packet.hh"
+#include "Packets/PacketType.hh"
#include "Packets/ParseInt.hh"
-#include "Packets/ParseArray.hh"
#include "Packets/PacketRegistry.hh"
+#include "Packets/PacketParser.hh"
+#include "Packets/ParseArray.hh"
#include "IpV4Packet.hh"
//#include "IpV6Packet.mpp"
namespace senf {
// See RFC2460
- template <class Iterator=nil, class IpV6Packet=nil>
- struct Parse_IpV6 : public ParserBase<Iterator,IpV6Packet>
+ struct Parse_IpV6 : public PacketParserBase
{
- template <class I, class P=nil>
- struct rebind { typedef Parse_IpV6<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_IpV6() {}
- Parse_IpV6(Iterator const & i) : ParserBase<Iterator,IpV6Packet>(i) {}
-
- static unsigned bytes() { return 40; }
+ SENF_PACKET_PARSER_NO_INIT(Parse_IpV6);
///////////////////////////////////////////////////////////////////////////
- typedef Parse_UIntField < 0, 4, Iterator > Parse_Version;
- typedef Parse_UIntField < 4, 12, Iterator > Parse_Class;
- typedef Parse_UIntField < 12, 32, Iterator > Parse_FlowLabel;
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_UInt16 < Iterator > Parse_16bit;
-
- typedef Parse_Array < 16, Parse_8bit, Iterator > Parse_Addr;
-
- Parse_Version version() const { return Parse_Version (this->i() ); }
- Parse_Class trafficClass() const { return Parse_Class (this->i() ); }
- Parse_FlowLabel flowLabel() const { return Parse_FlowLabel (this->i() ); }
- Parse_16bit length() const { return Parse_16bit (this->i() + 4 ); }
- Parse_8bit nextHeader() const { return Parse_8bit (this->i() + 6 ); }
- Parse_8bit hopLimit() const { return Parse_8bit (this->i() + 7 ); }
- Parse_Addr source() const { return Parse_Addr (this->i() + 8 ); }
- Parse_Addr destination() const { return Parse_Addr (this->i() + 24 ); }
+ typedef Parse_UIntField < 0, 4 > Parse_Version;
+ typedef Parse_UIntField < 4, 12 > Parse_Class;
+ typedef Parse_UIntField < 12, 32 > Parse_FlowLabel;
+ typedef Parse_UInt8 Parse_8bit;
+ typedef Parse_UInt16 Parse_16bit;
+
+ typedef Parse_Array < 16, Parse_8bit > Parse_Addr;
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((OverlayField)( version, Parse_Version ))
+ ((OverlayField)( trafficClass, Parse_Class ))
+ ((Field )( flowLabel, Parse_FlowLabel ))
+ ((Field )( length, Parse_16bit ))
+ ((Field )( nextHeader, Parse_8bit ))
+ ((Field )( hopLimit, Parse_8bit ))
+ ((Field )( source, Parse_Addr ))
+ ((Field )( destination, Parse_Addr )) );
+
+ void init() {
+ version() = 6;
+ }
};
- class IpV6Packet
- : public Packet,
- public Parse_IpV6<Packet::iterator, IpV6Packet>,
- public PacketRegistryMixin<IpTypes, IpV6Packet>
+ struct IpV6PacketType
+ : public PacketTypeBase,
+ public PacketTypeMixin<IpV6PacketType, IpTypes>
{
- using PacketRegistryMixin<IpTypes,IpV6Packet>::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<IpV6Packet>::ptr ptr;
-
- ///////////////////////////////////////////////////////////////////////////
-
- private:
- template <class Arg>
- IpV6Packet(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
+ typedef PacketTypeMixin<IpV6PacketType, IpTypes> mixin;
+ typedef ConcretePacket<IpV6PacketType> packet;
+ typedef Parse_IpV6 parser;
+
+ using mixin::nextPacketRange;
+ using mixin::nextPacketType;
+ using mixin::initSize;
+ using mixin::init;
+
+ static registry_key_t nextPacketKey(packet p)
+ { return p->nextHeader(); }
+
+ static void dump(packet p, std::ostream & os);
};
+ typedef IpV6PacketType::packet IpV6Packet;
+
}
///////////////////////////////hh.e////////////////////////////////////////
//#include "IpV6Packet.cci"
//#include "IpV6Packet.ct"
-#include "IpV6Packet.cti"
+//#include "IpV6Packet.cti"
#endif
\f
// Custom includes
#include "IpV6Packet.hh"
#include "Socket/INetAddressing.hh"
+#include "Packets/DataPacket.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
-
-BOOST_AUTO_UNIT_TEST(ipV6Packet_parser)
-{
- unsigned char data[] = { 0x60, 0x12, 0x20, 0x30,
- 0x01, 0x02, 0x03, 0x04,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f };
-
- typedef unsigned char * iterator;
- Parse_IpV6<iterator> p (data);
-
- BOOST_CHECK_EQUAL( unsigned(p.version()), 0x06u );
- BOOST_CHECK_EQUAL( unsigned(p.trafficClass()), 0x01u );
- BOOST_CHECK_EQUAL( unsigned(p.flowLabel()), 0x22030u );
- BOOST_CHECK_EQUAL( unsigned(p.length()), 0x0102u );
- BOOST_CHECK_EQUAL( unsigned(p.nextHeader()), 0x03u );
- BOOST_CHECK_EQUAL( unsigned(p.hopLimit()), 0x04u );
- BOOST_CHECK_EQUAL( INet6Address(p.source().range()).address() ,
- "1011:1213:1415:1617:1819:1a1b:1c1d:1e1f" );
- BOOST_CHECK_EQUAL( INet6Address(p.destination().range()).address() ,
- "2021:2223:2425:2627:2829:2a2b:2c2d:2e2f" );
-}
-
BOOST_AUTO_UNIT_TEST(ipV6Packet_packet)
{
unsigned char data[] = { 0x60, 0x12, 0x20, 0x30,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f };
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0xff };
- IpV6Packet::ptr p (Packet::create<IpV6Packet>(data, data+sizeof(data)));
+ senf::IpV6Packet p (senf::IpV6Packet::create(data));
- BOOST_CHECK_EQUAL( unsigned(p->version()), 0x06u );
- BOOST_CHECK_EQUAL( unsigned(p->trafficClass()), 0x01u );
- BOOST_CHECK_EQUAL( unsigned(p->flowLabel()), 0x22030u );
- BOOST_CHECK_EQUAL( unsigned(p->length()), 0x0102u );
- BOOST_CHECK_EQUAL( unsigned(p->nextHeader()), 0x03u );
- BOOST_CHECK_EQUAL( unsigned(p->hopLimit()), 0x04u );
- BOOST_CHECK_EQUAL( INet6Address(p->source().range()).address() ,
+ BOOST_CHECK_EQUAL( p->version(), 0x06u );
+ BOOST_CHECK_EQUAL( p->trafficClass(), 0x01u );
+ BOOST_CHECK_EQUAL( p->flowLabel(), 0x22030u );
+ BOOST_CHECK_EQUAL( p->length(), 0x0102u );
+ BOOST_CHECK_EQUAL( p->nextHeader(), 0x03u );
+ BOOST_CHECK_EQUAL( p->hopLimit(), 0x04u );
+ BOOST_CHECK_EQUAL( senf::INet6Address(p->source()).address() ,
"1011:1213:1415:1617:1819:1a1b:1c1d:1e1f" );
- BOOST_CHECK_EQUAL( INet6Address(p->destination().range()).address() ,
+ BOOST_CHECK_EQUAL( senf::INet6Address(p->destination()).address() ,
"2021:2223:2425:2627:2829:2a2b:2c2d:2e2f" );
- BOOST_CHECK( p->next() );
- BOOST_CHECK( p->next()->is<DataPacket>() );
- BOOST_CHECK_EQUAL( p->next()->size(), 0u );
+ BOOST_CHECK( p.next() );
+ BOOST_CHECK( p.next().is<senf::DataPacket>() );
+ BOOST_CHECK_EQUAL( p.next().size(), 1u );
}
///////////////////////////////cc.e////////////////////////////////////////
///////////////////////////////cc.p////////////////////////////////////////
namespace {
- senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::UDPPacket>
+ senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::UDPPacketType>
registerUDPPacket (17);
}
-prefix_ void senf::UDPPacket::v_nextInterpreter()
- const
-{
- registerInterpreter<DataPacket>(begin()+bytes(),end());
-}
-
-prefix_ void senf::UDPPacket::v_finalize()
-{}
-
-prefix_ void senf::UDPPacket::v_dump(std::ostream & os)
- const
+prefix_ void senf::UDPPacketType::dump(packet p, std::ostream & os)
{
os << "UDP:\n"
- << " source port : " << source() << "\n"
- << " dest port : " << destination() << "\n"
- << " length : " << length() << "\n"
- << " crc : " << std::hex << crc() << std::dec << "\n";
+ << " source port : " << p->source() << "\n"
+ << " dest port : " << p->destination() << "\n"
+ << " length : " << p->length() << "\n"
+ << " crc : " << std::hex << p->crc() << std::dec << "\n";
}
///////////////////////////////cc.e////////////////////////////////////////
#define HH_UDPPacket_ 1
// Custom includes
-#include "Packets/Packet.hh"
+#include "Packets/PacketType.hh"
#include "Packets/ParseInt.hh"
-#include "Packets/ParseArray.hh"
#include "Packets/PacketRegistry.hh"
+#include "Packets/PacketParser.hh"
//#include "UDPPacket.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
// See RFC768
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_UDP : public ParserBase<Iterator,IPacket>
+ struct Parse_UDP : public PacketParserBase
{
- template <class I, class P=nil>
- struct rebind { typedef Parse_UDP<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_UDP() {}
- Parse_UDP(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- static unsigned bytes() { return 8; }
+ SENF_PACKET_PARSER_INIT(Parse_UDP);
///////////////////////////////////////////////////////////////////////////
- typedef Parse_UInt16 < Iterator > Parse_16bit;
-
- Parse_16bit source() const { return Parse_16bit (this->i() ); }
- Parse_16bit destination() const { return Parse_16bit (this->i() + 2 ); }
- Parse_16bit length() const { return Parse_16bit (this->i() + 4 ); }
- Parse_16bit crc() const { return Parse_16bit (this->i() + 6 ); }
+ typedef Parse_UInt16 Parse_16bit;
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((Field)( source, Parse_16bit ))
+ ((Field)( destination, Parse_16bit ))
+ ((Field)( length, Parse_16bit ))
+ ((Field)( crc, Parse_16bit )) );
};
- class UDPPacket
- : public Packet,
- public Parse_UDP<Packet::iterator, UDPPacket>
+ struct UDPPacketType
+ : public PacketTypeBase,
+ public PacketTypeMixin<UDPPacketType>
{
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
+ typedef PacketTypeMixin<UDPPacketType> mixin;
+ typedef ConcretePacket<UDPPacketType> packet;
+ typedef Parse_UDP parser;
- typedef ptr_t<UDPPacket>::ptr ptr;
+ using mixin::nextPacketRange;
+ using mixin::initSize;
+ using mixin::init;
- ///////////////////////////////////////////////////////////////////////////
-
- private:
- template <class Arg>
- UDPPacket(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
+ static void dump(packet p, std::ostream & os);
};
+
+ typedef UDPPacketType::packet UDPPacket;
}
///////////////////////////////hh.e////////////////////////////////////////
//#include UDPPacket.cci"
//#include "UDPPacket.ct"
-#include "UDPPacket.cti"
+//#include "UDPPacket.cti"
#endif
\f
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
-
-BOOST_AUTO_UNIT_TEST(udpPacket_parser)
-{
- unsigned char data[] = { 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08
- };
-
- typedef unsigned char * iterator;
- Parse_UDP<iterator> p(data);
-
- BOOST_CHECK_EQUAL( p.source(), 0x0102 );
- BOOST_CHECK_EQUAL( p.destination(), 0x0304 );
- BOOST_CHECK_EQUAL( p.length(), 0x0506 );
- BOOST_CHECK_EQUAL( p.crc(), 0x0708 );
-
-}
-
-
BOOST_AUTO_UNIT_TEST(udpPacket_packet)
{
0x05, 0x06, 0x07, 0x08
};
- UDPPacket::ptr p (Packet::create<UDPPacket>(data, data+sizeof(data)));
+ senf::UDPPacket p (senf::UDPPacket::create(data));
BOOST_CHECK_EQUAL( p->source(), 0x0102 );
BOOST_CHECK_EQUAL( p->destination(), 0x0304 );
PROJECT_NAME = libPackets
TAGFILES = "$(TOPDIR)/Utils/doc/Utils.tag"
GENERATE_TAGFILE = doc/Packets.tag
-INPUT = . DefaultBundle RTPBundle
\ No newline at end of file
+#INPUT = . DefaultBundle RTPBundle
+INPUT = .
\ No newline at end of file
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of inline template functions
-
-//#include "GenericPacket.ih"
-
-// Custom includes
-
-#define prefix_ inline
-///////////////////////////////cti.p///////////////////////////////////////
-
-template <unsigned HEADER, unsigned TRAILER>
-template <class Arg>
-prefix_ senf::GenericPacket<HEADER,TRAILER>::GenericPacket(Arg const & arg)
-: Packet(arg)
-{}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::init()
-{
- insert(begin(),HEADER,0);
- insert(end(),TRAILER,0);
-}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ typename senf::GenericPacket<HEADER,TRAILER>::iterator
-senf::GenericPacket<HEADER,TRAILER>::begin_header()
- const
-{
- return this->begin();
-}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ typename senf::GenericPacket<HEADER,TRAILER>::iterator
-senf::GenericPacket<HEADER,TRAILER>::end_header()
- const
-{
- return this->begin() + HEADER;
-}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ typename senf::GenericPacket<HEADER,TRAILER>::size_type
-senf::GenericPacket<HEADER,TRAILER>::header_len()
-{
- return HEADER;
-}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ typename senf::GenericPacket<HEADER,TRAILER>::iterator
-senf::GenericPacket<HEADER,TRAILER>::begin_trailer()
- const
-{
- return this->end() - TRAILER;
-}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ typename senf::GenericPacket<HEADER,TRAILER>::iterator
-senf::GenericPacket<HEADER,TRAILER>::end_trailer()
- const
-{
- return this->end();
-}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ typename senf::GenericPacket<HEADER,TRAILER>::size_type
-senf::GenericPacket<HEADER,TRAILER>::trailer_len()
-{
- return TRAILER;
-}
-
-///////////////////////////////cti.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef HH_GenericPacket_
-#define HH_GenericPacket_ 1
-
-// Custom includes
-#include "Packet.hh"
-
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-
-
- /** \brief General packet comprised of header, trailer and payload
-
- This class implements a generic packet with three sections: a
- header, a trailer and a payload section. The header and
- trailer are not interpreted in any way. The payload can be
- manually chained to any packet interpreter.
- */
- template <unsigned HEADER, unsigned TRAILER=0>
- class GenericPacket : public Packet
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef typename Packet::ptr_t<GenericPacket>::ptr ptr;
- typedef iterator byte_iterator;
-
- ///////////////////////////////////////////////////////////////////////////
-
- void init();
-
- iterator begin_header() const;
- iterator end_header() const;
- static size_type header_len();
-
- iterator begin_trailer() const;
- iterator end_trailer() const;
- static size_type trailer_len();
-
- static bool check(iterator const & b, iterator const & e)
- { return unsigned(e - b) >= HEADER + TRAILER; }
-
- protected:
-
- private:
- template <class Arg>
- GenericPacket(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
- };
-
-}
-
-///////////////////////////////hh.e////////////////////////////////////////
-//#include "GenericPacket.cci"
-#include "GenericPacket.ct"
-#include "GenericPacket.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline non-template functions
+/** \file
+ \brief Packet non-inline non-template implementation */
+#include "PacketInterpreter.hh"
#include "Packet.hh"
-#include "Packet.ih"
+//#include "Packet.ih"
// Custom includes
-#include <boost/utility.hpp> // for next/prior
+#include "DataPacket.hh"
+//#include "Packet.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-// REFERENCE COUNTING
-///////////////////////////////////////////////////////////////////////////
-
-// We manage TWO reference counts:
-//
-// - The first reference counts lives wihin PacketImpl. It counts the
-// number of references to the PacketImpl instance
-//
-// - The second reference count lives with the Packet interpreters. It
-// counts the number of external references to the Packet facades.
-//
-// The PacketImpl refcount is always the sum of all it's Packet
-// interpreter member refcounts.
-//
-// The Packet facades are referenced from two sides:
-//
-// - From the user. These references are counted in the Packet
-// refcount.
-//
-// - From the list of interpreters. These references are *not*
-// counted.
-//
-// The Packet facades have an impl_ member. This is set to non-0 only,
-// as long as the Packet is a list member. The Packet may be deleted,
-// when impl_ == 0 and refcount_ == 0.
-
-// class ListPacketDeleter
-
-// This is the custom deleter used for the pointers in the
-// interpreters list. This deleter is only called, when the Packet is
-// removed from the interpreters list.
-prefix_ void senf::impl::ListPacketDeleter::operator()(Packet * p)
-{
- PacketImpl * impl = PacketImpl::impl(p);
- if (impl->releaseInterpreter(p))
- delete impl;
-}
-
-// struct PacketImpl
-
-prefix_ senf::Packet::interpreter_list::iterator
-senf::impl::PacketImpl::appendInterpreter(Packet * p)
-{
- BOOST_ASSERT( p->impl_ == 0 );
-
- this->refcount_ += p->refcount_;
- SATCOM_PKF_REFC_MSG("] PacketImpl::appendInterpreter (" << this << "): refcount_ = " << refcount_ << "\n");
- p->impl_ = this;
- this->interpreters_.push_back(
- boost::shared_ptr<Packet>(p, impl::ListPacketDeleter()));
-
- p->self_ = boost::prior(this->interpreters_.end());
- return p->self_;
-}
-
-prefix_ senf::Packet::interpreter_list::iterator
-senf::impl::PacketImpl::prependInterpreter(Packet * p)
-{
- BOOST_ASSERT( p->impl_ == 0 );
-
- this->refcount_ += p->refcount_;
- SATCOM_PKF_REFC_MSG("] PacketImpl::prependInterpreter (" << this << "): refcount_ = " << refcount_ << "\n");
- p->impl_ = this;
- this->interpreters_.push_front(
- boost::shared_ptr<Packet>(p, impl::ListPacketDeleter()));
-
- p->self_ = this->interpreters_.begin();
- return p->self_;
-}
-
-// Called, whenever a Packet is removed from the list by the
-// ListPacketDeleter;
-prefix_ bool senf::impl::PacketImpl::releaseInterpreter(Packet * p)
-{
- // We have to be extra careful here: This method might be called
- // AFTER the PacketImpl instance has already been destructed while
- // destructing the interpreters list !!
- // If p->refcount_ is > 0 however we know, that this->refcount_
- // must also be > 0 ...
- // So we have to make sure never to access this if p->refcount_==0
- BOOST_ASSERT( p->impl_ == this );
- bool rv (false);
- if (p->refcount_ > 0) {
- this->refcount_ -= p->refcount_;
- rv = !this->refcount_;
- SATCOM_PKF_REFC_MSG("] PacketImpl::releaseInterpreter (" << this << "): refcount_ = " << refcount_ << "\n");
- }
- if (p->unlink())
- delete p;
- return rv;
-}
-
-namespace {
- bool whenceCmp(unsigned a, unsigned b, bool end, senf::Packet::Whence whence)
- {
- using senf::Packet;
- return ((whence == Packet::OUTSIDE && ! end)
- || whence == Packet::BEFORE
- || (whence == Packet::INSIDE && end)) ? a>=b : a>b;
- }
-}
-
-prefix_ void
-senf::impl::PacketImpl::updateIterators(Packet::size_type index,
- Packet::difference_type n,
- Packet::interpreter_list::iterator self,
- Packet::Whence whence)
-{
- Packet::interpreter_list::iterator i (interpreters_.begin());
- Packet::interpreter_list::iterator const e (interpreters_.end());
- Packet::Whence w (whence == Packet::AUTO ? Packet::INSIDE : whence);
- for (;i!=e;++i) {
- if (whenceCmp((*i)->end_,index,true,w))
- if (n<0 && (*i)->end_ < index-n)
- (*i)->end_ = index;
- else
- (*i)->end_ += n;
- if (whenceCmp((*i)->begin_,index,false,w))
- if (n<0 && (*i)->begin_ < index-n)
- (*i)->begin_ = index;
- else
- (*i)->begin_ += n;
- if (i == self && whence == Packet::AUTO) w = Packet::OUTSIDE;
- BOOST_ASSERT( (*i)->end_ >= (*i)->begin_ );
- }
-}
-
-prefix_ void senf::impl::PacketImpl::packet_add_ref(Packet const * p)
-{
- p->add_ref();
- if (p->impl_)
- p->impl_->add_ref();
-}
-
-prefix_ void senf::impl::PacketImpl::packet_release(Packet * p)
-{
- bool del (p->release());
- if (p->impl_ && p->impl_->release())
- // In this case, del is certainly false here. p might
- // however get deleted now.
- delete p->impl_;
- if (del)
- delete p;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// class Packet
-
-prefix_ senf::Packet::ptr senf::Packet::next()
+prefix_ senf::Packet senf::Packet::checkNext()
const
{
- interpreter_list::iterator n = boost::next(this->self_);
- if (n == this->impl_->interpreters_.end()) {
- if (this->parsed_)
- return ptr(0);
- /* \fixme v_nextInterpreter return bool? new Interpreter to be
- added ? hmm ... this however is quite suboptimal ... */
- this->v_nextInterpreter();
- this->parsed_ = true;
- n = boost::next(this->self_);
- if (n == this->impl_->interpreters_.end())
- return ptr(0);
+ PacketInterpreterBase::optional_range r (ptr()->nextPacketRange());
+ if (r && ! r->empty()) {
+ factory_t factory (ptr()->nextPacketType());
+ if (factory)
+ return parseNextAs(factory);
+ else
+ return parseNextAs<DataPacket>();
}
- // Re-converting the Packet to a smart pointer is correct here,
- // since the shared_ptr really uses the intrusive refcount which
- // makes this operation safe ...
- return ptr(n->get(),true);
+ return Packet();
}
-prefix_ senf::Packet::ptr senf::Packet::last()
+prefix_ senf::Packet senf::Packet::checkLast()
const
{
- Packet * p = this->impl_->interpreters_.back().get();
- while (! p->parsed_) {
- Packet * pp = p->next().get();
- if (pp) p = pp;
+ Packet p (*this);
+ Packet n (p.next());
+ while (n) {
+ p = n;
+ n = p.next();
}
- // Re-converting the to a smart pointer is correct here, since the
- // shared_ptr really uses the intrusive refcount which makes this
- // operation safe ...
- return ptr(p,true);
-}
-
-prefix_ void senf::Packet::i_registerInterpreter(Packet * p)
- const
-{
- BOOST_ASSERT( !p->impl_ );
- this->impl_->truncateInterpretersAfter(this);
- this->impl_->appendInterpreter(p);
- this->parsed_ = true;
-}
-
-prefix_ void senf::Packet::i_replaceInterpreter(Packet * p)
-{
- BOOST_ASSERT( !p->impl_ );
- // We need to increment the refcount of impl_ beforehand,
- // otherwise it might get deleted by the truncateInterpreters call
- boost::intrusive_ptr<impl::PacketImpl> impl (this->impl_,true);
- impl->truncateInterpreters(this);
- impl->appendInterpreter(p);
-}
-
-prefix_ void senf::Packet::i_setInterpreter(impl::PacketImpl * i)
-{
- // Using prependInterpreter makes this usable for both, the
- // create-from-data and wrap-packet constructors
- i->prependInterpreter(this);
-}
-
-prefix_ void senf::Packet::insert(iterator pos, byte v, Whence whence)
-{
- size_type index(pos-impl_->data_.begin());
- BOOST_ASSERT( index >= begin_ && index <= end_);
- impl_->data_.insert(pos,v);
- impl_->updateIterators(index,1,self_,whence);
-}
-
-prefix_ void senf::Packet::insert(iterator pos, size_type n, byte v, Whence whence)
-{
- size_type index(pos-impl_->data_.begin());
- BOOST_ASSERT( index >= begin_ && index <= end_ );
- impl_->data_.insert(pos,n,v);
- impl_->updateIterators(index,n,self_,whence);
-}
-
-prefix_ void senf::Packet::erase(iterator pos)
-{
- size_type index(pos-impl_->data_.begin());
- BOOST_ASSERT( index >= begin_ && index < end_ );
- impl_->data_.erase(pos);
- impl_->updateIterators(index,-1,self_,INSIDE);
-}
-
-prefix_ void senf::Packet::erase(iterator first, iterator last)
-{
- size_type index(first-impl_->data_.begin());
- size_type sz(last-first);
- BOOST_ASSERT( index >= begin_ && index < end_ && sz <= end_-index );
- /** \todo Here we should assert, that no bytes belonging to the
- next iterator are deleted ... */
- impl_->data_.erase(first,last);
- impl_->updateIterators(index,-sz,self_,INSIDE);
-}
-
-prefix_ void senf::Packet::dump(std::ostream & os)
- const
-{
- v_dump(os);
- ptr p (next());
- if (p)
- p->dump(os);
+ return p;
}
-//////////////////////////////cc.e////////////////////////////////////////
+///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
+//#include "Packet.mpp"
\f
// Local Variables:
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of inline non-template functions
-
-#include "Packet.ih"
+/** \file
+ \brief Packet inline non-template implementation */
// Custom includes
#define prefix_ inline
///////////////////////////////cci.p///////////////////////////////////////
-prefix_ senf::impl::PacketImpl::PacketImpl()
- : data_(), interpreters_(), refcount_(1)
-{
- SATCOM_PKF_REFC_MSG("] PacketImpl::PacketImpl (" << this << "): refcount_ = 1\n");
-}
+///////////////////////////////////////////////////////////////////////////
+// senf::Packet
-prefix_ senf::impl::PacketImpl::PacketImpl(unsigned size, Packet::byte initValue)
- : data_(size,initValue), interpreters_(), refcount_(1)
-{
- SATCOM_PKF_REFC_MSG("] PacketImpl::PacketImpl (" << this << "): refcount_ = 1\n");
-}
+// public structors
-prefix_ senf::impl::PacketImpl::~PacketImpl()
-{
- BOOST_ASSERT( !refcount_ );
- SATCOM_PKF_REFC_MSG("] PacketImpl::~PacketImpl (" << this << ")\n");
-}
+prefix_ senf::Packet::Packet()
+{}
-// PacketImpl::add_ref and PacketImpl::release are only called from
-// intrusive_ptr_add_ref and intrusive_ptr_release
-prefix_ void senf::impl::PacketImpl::add_ref()
+prefix_ senf::Packet senf::Packet::clone()
+ const
{
- ++refcount_;
- SATCOM_PKF_REFC_MSG("] PacketImpl::add_ref (" << this << "): refcount_ = " << refcount_ << "\n");
+ return Packet(ptr()->clone());
}
-prefix_ bool senf::impl::PacketImpl::release()
-{
- BOOST_ASSERT( refcount_ > 0 );
- --refcount_;
- SATCOM_PKF_REFC_MSG("] PacketImpl::release (" << this << "): refcount_ = " << refcount_ << "\n");
- return ! refcount_;
-}
+// Interpreter chain access
-prefix_ void senf::impl::PacketImpl::truncateInterpreters(Packet const * p)
+prefix_ senf::Packet senf::Packet::next()
+ const
{
- BOOST_ASSERT( p->impl_ == this );
- this->interpreters_.erase(p->self_,this->interpreters_.end());
+ PacketInterpreterBase::ptr p (ptr()->next());
+ return !p && ptr()->nextPacketRange() ? checkNext() : Packet(p);
}
-prefix_ void senf::impl::PacketImpl::truncateInterpretersAfter(Packet const * p)
+prefix_ senf::Packet senf::Packet::prev()
+ const
{
- BOOST_ASSERT( p->impl_ == this );
- this->interpreters_.erase(boost::next(p->self_),this->interpreters_.end());
+ return Packet(ptr()->prev());
}
-prefix_ senf::impl::PacketImpl* senf::impl::PacketImpl::impl(Packet const * p)
+prefix_ senf::Packet senf::Packet::first()
+ const
{
- return p->impl_;
+ return Packet(ptr()->first());
}
-/*
-prefix_ std::ostream & senf::operator<<(std::ostream & os, Packet const & packet)
+prefix_ senf::Packet senf::Packet::last()
+ const
{
- packet.dump(os);
- return os;
+ Packet p (ptr()->last());
+ return p.next() ? checkLast() : p;
}
-*/
-// These methods are called by the user codes Packet::ptr's. They
-// refcount both the Packet and the owning PacketImpl.
-prefix_ void senf::intrusive_ptr_add_ref(Packet const * p)
+prefix_ senf::Packet senf::Packet::parseNextAs(factory_t factory)
+ const
{
- impl::PacketImpl::packet_add_ref(p);
+ return Packet(ptr()->parseNextAs(factory));
}
-prefix_ void senf::intrusive_ptr_release(Packet * p)
+prefix_ senf::Packet senf::Packet::append(Packet packet)
+ const
{
- impl::PacketImpl::packet_release(p);
+ return Packet(ptr()->append(packet.ptr()));
}
-prefix_ void senf::impl::intrusive_ptr_add_ref(PacketImpl * p)
-{
- p->add_ref();
-}
+// Data access
-prefix_ void senf::impl::intrusive_ptr_release(PacketImpl * p)
+prefix_ senf::PacketData & senf::Packet::data()
+ const
{
- if (p->release())
- delete p;
+ return ptr()->data();
}
-///////////////////////////////////////////////////////////////////////////
-// class Packet
-
-prefix_ senf::Packet::iterator senf::Packet::begin()
+prefix_ senf::Packet::size_type senf::Packet::size()
const
{
- return impl_->data_.begin()+begin_;
+ return data().size();
}
-prefix_ senf::Packet::iterator senf::Packet::end()
+
+// Other methods
+
+prefix_ bool senf::Packet::operator==(Packet other)
const
{
- return impl_->data_.begin()+end_;
+ return ptr() == other.ptr();
}
-prefix_ size_t senf::Packet::size()
+prefix_ void senf::Packet::finalize()
const
{
- return end_-begin_;
+ ptr()->finalize();
}
-prefix_ senf::Packet::ptr senf::Packet::prev()
+prefix_ void senf::Packet::dump(std::ostream & os)
const
{
- if (this->self_ == this->impl_->interpreters_.begin())
- return ptr(0);
- // Re-converting the to a smart pointer is correct here, since the
- // shared_ptr really uses the intrusive refcount which makes this
- // operation safe ...
- return ptr(boost::prior(this->self_)->get(),true);
+ last(); // Make sure the packet is complete
+ ptr()->dump(os);
}
-prefix_ senf::Packet::ptr senf::Packet::head()
+prefix_ senf::TypeIdValue senf::Packet::typeId()
const
{
- // Re-converting the to a smart pointer is correct here, since the
- // shared_ptr really uses the intrusive refcount which makes this
- // operation safe ...
- return ptr(this->impl_->interpreters_.front().get(),true);
+ return ptr()->typeId();
}
-prefix_ senf::Packet::~Packet()
+prefix_ senf::Packet::factory_t senf::Packet::factory()
+ const
{
- /** \todo This is sad ... we cannot check this since this assertion fails at the moment if the
- Packet constructor throws ... hrmpf ... we really should initialize refcount_ to 0 and
- remove the 'false' argument to the ptr constructor in create */
- // BOOST_ASSERT( !this->refcount_ && !this->impl_ );
- SATCOM_PKF_REFC_MSG("] Packet::~Packet (" << this << ")\n");
+ return ptr()->factory();
}
-prefix_ void senf::Packet::add_ref()
+prefix_ bool senf::Packet::boolean_test()
const
{
- ++this->refcount_;
- SATCOM_PKF_REFC_MSG("] Packet::add_ref (" << this << "): refcount_ = " << this->refcount_ << "\n");
+ return packet_ && packet_->valid();
}
-prefix_ bool senf::Packet::release()
-{
- BOOST_ASSERT( this->refcount_ > 0 );
- --this->refcount_;
- SATCOM_PKF_REFC_MSG("] Packet::release (" << this << "): refcount_ = " << this->refcount_ << "\n");
- return !this->refcount_ && !this->impl_;
-}
+// protected members
+
+prefix_ senf::Packet::Packet(PacketInterpreterBase::ptr packet)
+ : packet_(packet)
+{}
-prefix_ bool senf::Packet::unlink()
+prefix_ senf::PacketInterpreterBase::ptr senf::Packet::ptr()
+ const
{
- SATCOM_PKF_REFC_MSG("] Packet::unlink (" << this << "): refcount_ = " << this->refcount_ << "\n");
- this->impl_ = 0;
- this->begin_ = this->end_;
- return !this->refcount_;
+ BOOST_ASSERT(packet_);
+ return packet_;
}
///////////////////////////////cci.e///////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline template functions
+/** \file
+ \brief Packet non-inline template implementation */
-#include "Packet.ih"
+//#include "Packet.ih"
// Custom includes
-#include <algorithm>
-#include "ParserBase.hh"
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
-template <class OtherPacket, class InputIterator>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr
-senf::Packet::create(InputIterator b, InputIterator e)
-{
- boost::intrusive_ptr<impl::PacketImpl> impl (new impl::PacketImpl(b,e),false);
- if (!check<OtherPacket>(impl->data_.begin(),impl->data_.end()))
- throw TruncatedPacketException();
- typename ptr_t<OtherPacket>::ptr p (new OtherPacket(PacketOp_set(impl.get())), false);
- return p;
-}
+///////////////////////////////////////////////////////////////////////////
+// senf::Packet
template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::create()
-{
- boost::intrusive_ptr<impl::PacketImpl> impl (
- new impl::PacketImpl(min_bytes<OtherPacket>(),0));
- typename ptr_t<OtherPacket>::ptr p (new OtherPacket(PacketOp_set(impl.get())), false);
- p->init();
- return p;
-}
-
-template <class OuterPacket>
-prefix_ typename senf::Packet::ptr_t<OuterPacket>::ptr
-senf::Packet::create(Packet::ptr payload)
-{
- /** \todo should I instead of using head() throw away all
- interpreters before payload? ... probably yes ... */
- payload->insert(payload->head()->begin(),min_bytes<OuterPacket>(),0);
- typename ptr_t<OuterPacket>::ptr p (new OuterPacket(PacketOp_set(payload->impl_)));
- p->init();
- return p;
-}
-
-template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::reinterpret()
-{
- // THIS INVALIDATES this !!!!!!!
- if (!check<OtherPacket>(begin(),end()))
- throw TruncatedPacketException();
- typename ptr_t<OtherPacket>::ptr p (new OtherPacket(PacketOp_replace(this)),false);
- return p;
-}
-
-template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr
-senf::Packet::registerInterpreter(raw_container::iterator begin,
- raw_container::iterator end)
+prefix_ OtherPacket senf::Packet::findNext(NoThrow_t)
const
{
- if (!check<OtherPacket>(begin,end))
- throw TruncatedPacketException();
- typename ptr_t<OtherPacket>::ptr p (
- new OtherPacket(PacketOp_register(begin-impl_->data_.begin(),
- end-impl_->data_.begin(),
- this)),
- false);
- return p;
+ Packet p (*this);
+ while (p && ! p.is<OtherPacket>())
+ p = p.next();
+ if (p)
+ return p.as<OtherPacket>();
+ else
+ return OtherPacket();
}
-#define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 9, "Packets/Packet.mpp", 4))
-#include BOOST_PP_ITERATE()
-
template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::find_next()
+prefix_ OtherPacket senf::Packet::findPrev(NoThrow_t)
const
{
- ptr p (next());
- while (p && !p->is<OtherPacket>())
- p = p->next();
- return p->as<OtherPacket>();
-}
-
-template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::find_prev()
- const
-{
- ptr p (prev());
- while (p && !p->is<OtherPacket>())
- p = p->prev();
- return p->as<OtherPacket>();
-}
-
-template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::get_next()
- const
-{
- typename ptr_t<OtherPacket>::ptr p (find_next<OtherPacket>());
- BOOST_ASSERT(p);
- return p;
-}
-
-template <class OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::get_prev()
- const
-{
- typename ptr_t<OtherPacket>::ptr p (find_prev<OtherPacket>());
- BOOST_ASSERT(p);
- return p;
-}
-
-template <class InputIterator>
-prefix_ void senf::Packet::insert(iterator pos, InputIterator f, InputIterator l,
- Whence whence)
-{
- size_type index(pos-impl_->data_.begin());
- BOOST_ASSERT( index >= begin_ && index <= end_ );
- size_type sz (impl_->data_.size());
- impl_->data_.insert(pos,f,l);
- impl_->updateIterators(index,impl_->data_.size()-sz,self_,whence);
+ Packet p (*this);
+ while (p && ! p.is<OtherPacket>())
+ p = p.prev();
+ if (p)
+ return p.as<OtherPacket>();
+ else
+ return OtherPacket();
}
///////////////////////////////ct.e////////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of inline template functions
+/** \file
+ \brief Packet inline template implementation */
-#include "Packet.ih"
+//#include "Packet.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <typename OtherPacket>
+///////////////////////////////////////////////////////////////////////////
+// senf::Packet
+
+// conversion constructors
+
+template <class PacketType>
+prefix_ senf::Packet::Packet(ConcretePacket<PacketType> packet)
+ : packet_(packet.ptr())
+{}
+
+// interpreter chain access
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::parseNextAs()
+ const
+{
+ return OtherPacket(ptr()->parseNextAs<typename OtherPacket::type>());
+}
+
+template <class OtherPacket>
prefix_ bool senf::Packet::is()
const
{
- return dynamic_cast<OtherPacket const *>(this);
+ return ptr()->is<typename OtherPacket::type>();
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::as()
+ const
+{
+ return OtherPacket(ptr()->as<typename OtherPacket::type>());
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::next()
+ const
+{
+ OtherPacket p (next<OtherPacket>(nothrow));
+ if (!p) throw InvalidPacketChainException();
+ return p;
+}
+
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::next(NoThrow_t)
+ const
+{
+ Packet p (next());
+ return p ? p.findNext<OtherPacket>(nothrow) : OtherPacket();
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::prev()
+ const
+{
+ OtherPacket p (prev<OtherPacket>(nothrow));
+ if (!p) throw InvalidPacketChainException();
+ return p;
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::prev(NoThrow_t)
+ const
+{
+ Packet p (prev());
+ return p ? p.findPrev<OtherPacket>(nothrow) : OtherPacket();
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::findNext()
+ const
+{
+ OtherPacket p (findNext<OtherPacket>(nothrow));
+ if (!p) throw InvalidPacketChainException();
+ return p;
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::findPrev()
+ const
+{
+ OtherPacket p (findPrev<OtherPacket>(nothrow));
+ if (!p) throw InvalidPacketChainException();
+ return p;
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::last()
+ const
+{
+ return last().findPrev<OtherPacket>();
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::last(NoThrow_t)
+ const
+{
+ return last().findPrev<OtherPacket>(nothrow);
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::first()
+ const
+{
+ return first().findNext<OtherPacket>();
+}
+
+template <class OtherPacket>
+prefix_ OtherPacket senf::Packet::first(NoThrow_t)
+ const
+{
+ return first().findNext<OtherPacket>(nothrow);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::ConcretePacket<PacketType>
+
+// structors and default members
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>::ConcretePacket()
+{}
+
+template <class PacketType>
+prefix_ typename senf::ConcretePacket<PacketType>::factory_t
+senf::ConcretePacket<PacketType>::factory()
+{
+ return interpreter::factory();
+}
+
+// Create completely new packet
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::create()
+{
+ return ConcretePacket(interpreter::create());
+}
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::create(NoInit_t)
+{
+ return ConcretePacket(interpreter::create(interpreter::noinit));
+}
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::create(size_type size)
+{
+ return ConcretePacket(interpreter::create(size));
+}
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::create(size_type size, NoInit_t)
+{
+ return ConcretePacket(interpreter::create(size,interpreter::noinit));
+}
+
+template <class PacketType>
+template <class ForwardReadableRange>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::create(ForwardReadableRange const & range)
+{
+ return ConcretePacket(interpreter::create(range));
+}
+
+// Create packet as new packet after a given packet
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createAfter(Packet packet)
+{
+ return ConcretePacket(interpreter::createAfter(packet.ptr()));
}
-template <typename OtherPacket>
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::as()
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createAfter(Packet packet, NoInit_t)
{
- return typename ptr_t<OtherPacket>::ptr(dynamic_cast<OtherPacket*>(this),true);
+ return ConcretePacket(interpreter::createAfter(packet.ptr(),interpreter::noinit));
}
-// This constructor appends a new interreter to the interpreter chain
-// of an existing Packet
-template <class Operation>
-prefix_ senf::Packet::Packet(Operation const & arg)
- : impl_(0), begin_(arg.begin()), end_(arg.end()), self_(),
- parsed_(false), refcount_(1)
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createAfter(Packet packet, size_type size)
{
- SATCOM_PKF_REFC_MSG("] Packet::Packet (" << this << "): refcount_ = 1\n");
- arg(this);
+ return ConcretePacket(interpreter::createAfter(packet.ptr(), size));
}
-template <class InputIterator>
-prefix_ senf::impl::PacketImpl::PacketImpl(InputIterator begin, InputIterator end)
- : data_(begin, end), interpreters_(), refcount_(1)
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createAfter(Packet packet, size_type size, NoInit_t)
+{
+ return ConcretePacket(interpreter::createAfter(packet.ptr(), size, interpreter::noinit));
+}
+
+template <class PacketType>
+template <class ForwardReadableRange>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createAfter(Packet packet, ForwardReadableRange const & range)
+{
+ return ConcretePacket(interpreter::createAfter(packet.ptr(), range));
+}
+
+// Create packet as new packet (header) before a given packet
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createBefore(Packet packet)
+{
+ return ConcretePacket(interpreter::createBefore(packet.ptr()));
+}
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::createBefore(Packet packet, NoInit_t)
+{
+ return ConcretePacket(interpreter::createBefore(packet.ptr(), interpreter::noinit));
+}
+
+// Create a clone of the current packet
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>
+senf::ConcretePacket<PacketType>::clone()
+ const
+{
+ return ConcretePacket(ptr()->clone());
+}
+
+// Field access
+
+template <class PacketType>
+prefix_ typename senf::ConcretePacket<PacketType>::interpreter::parser *
+senf::ConcretePacket<PacketType>::operator->()
+ const
+{
+ return ptr()->fields_p();
+}
+
+// private members
+
+template <class PacketType>
+prefix_ senf::ConcretePacket<PacketType>::ConcretePacket(typename interpreter::ptr packet_)
+ : Packet(packet_)
+{}
+
+template <class PacketType>
+prefix_ typename senf::ConcretePacket<PacketType>::interpreter::ptr
+senf::ConcretePacket<PacketType>::ptr()
+ const
{
- SATCOM_PKF_REFC_MSG("] PacketImpl::PacketImpl (" << this << "): refcount_ = 1\n")
+ return boost::static_pointer_cast< PacketInterpreter<PacketType> >(Packet::ptr());
}
///////////////////////////////cti.e///////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Main packet interface
-
- \todo Implement assign() method akin to reinterpret(). However,
- instead of using the data already present, assign() will replace
- the date of the current packet with the given Packet.
-
- \todo Implement wrapping-constructor. Somehow we want to have a
- constructor, which allows creating a chain of packet interpreters
- with as little overhead as possible.
-
- \todo Document the additional concrete Packet facade requirements
- explicitly and not only within the Parser requirements (check(),
- bytes() and min_bytes() members ...)
-
- \todo Implement special container replacing vector which manages
- some headroom to allow efficient insertion of elements at the
- beginning. This really is just another type of dequeue
- implementation.
- */
+ \brief Packet public header */
#ifndef HH_Packet_
#define HH_Packet_ 1
// Custom includes
-#include <boost/utility.hpp> // for boost::noncopyable
-#include <boost/cstdint.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/intrusive_ptr.hpp>
-#include <list>
-#include <vector>
-#include <iostream>
+#include <boost/operators.hpp>
+
+#include "Utils/Exception.hh"
+#include "Utils/SafeBool.hh"
+#include "PacketInterpreter.hh"
-#include "Packet.mpp"
-// ////////////////////////////hh.p////////////////////////////////////////
+//#include "Packet.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
- namespace impl { template <class OtherPacket> class PkReg_EntryImpl; }
- namespace impl { class PacketImpl; }
-
- /** \brief Basic interface to all packet facades
-
- \section packet_overview Overview
-
- This class is the base class of all Packets. It implements the
- generic Packet interface and provides the packet management
- framework. senf::Packet manages the necessary memory
- resources and controls the chain of packet interpreters.
-
- The Packet user always interfaces with the pkf via a Packet
- derived class. This is the only external entity ever held by a
- library user. The interface is implemented using a reference
- counted smart pointer, so resource management is quasi
- automatic.
-
- \image html structure.png Overview
-
- Internally, every Packet references a PacketImpl instance which
- manages the raw packet data and the interpreter list. This raw
- data is interpreted by the concrete Packet derived class
- according to the definition of that derived classes packet
- type (i.e. EthernetPacket or UDPPacket).
-
- Packet provides several interfaces:
-
- - Creation of Packet instances: create()
-
- - Access to the chain of interpreters: next(), prev(), head(),
- last(), find_next(), find_prev(), get_next(), get_prev(),
- is(), as() and reinterpret()
-
- - Access to the raw packet data: begin(), end(), size(),
- insert() and erase()
-
- - An interface to the derived class: v_nextInterpreter(),
- v_finalize(), registerInterpreter()
-
-
- \section packet_der Implementing new Packet facades
-
- To implement a new Packet facade, publically derive from
- Packet. You need to implement the following minimal interface:
-
- - You need to provide a new #ptr typedef
-
- - You have to implement v_nextInterpreter() and v_finalize()
-
- - The constructor should be private
-
- - You must make Packet a \c friend of the new Packet facade
-
- - You must implement a static check() method which validates
- a byte region as your new Packet
-
- \code
- class ExamplePacket
- : public senf::Packet
- {
- public:
- typedef ptr_t<ExamplePacket>::ptr ptr;
-
- static bool check(Packet::iterator begin, Packet::iterator end)
- {
- // Validate, that the region [begin,end) can be
- // interpreted as an ExamplePacket without risking
- // memory access violations.
- }
-
- private:
- template <class Arg>
- ExamplePacket(Arg arg [, other args ... ])
- : senf::Packet(arg)
- {}
-
- virtual void v_nextInterpreter() const
- {
- // NextPacketType and header_length of course
- // depend on the packet type
- registerInterpreter<NextPacketType>(begin()+header_length, end());
- }
-
- virtual void v_finalize()
- {
- // calculate checksum etc
- }
-
- friend class senf::Packet;
- };
- \endcode
-
- Please do not implement the methods inline to not clutter up
- the header file. This is done here in the example to simplify
- it. If a class is to be registered in some
- senf:PacketRegistry, it must not take any additional
- constructor parameters.
-
- After having implemented the bare framework, the most common
- way to implement access to the packets specific data is to use
- the parser framework by additionally inheriting a
- corresponding parser. This also automatically implements the
- check() method, which is provided by the Parser.
-
- In the following example we only show the differences from the
- previous example:
-
- \code
- class ExamplePacket
- : public senf::Packet,
- public Parse_Example<senf::Packet::iterator,
- ExamplePacket>
- {
-
- // check does not need to be implemented here, it is
- // inherited from the parser
-
- private:
- template <class InputIterator>
- ExamplePacket(InputIterator begin, InputIterator end)
- : senf::Packet(begin,end)
- {}
- };
- \endcode
-
- See the senf::ParserBase Documentation for how to
- implement Parse_Example.
-
- The implementation of v_nextInterpreter most of the time
- relies on some packet registry. This is simplified using the
- senf::PacketRegistryMixin class as follows. Again, we
- only show the differences from the preceding Example:
-
- \code
- struct ExampleRegistry {
- type boost::uint16_t key_t;
- };
-
- class ExamplePacket
- : public senf::Packet,
- public Parse_Example<senf::Packet::iterator,
- ExamplePacket>,
- public senf::PacketRegistryMixin<ExampleRegistry,
- ExamplePacket>
- {
- using senf::Packet::registerInterpreter;
- using senf::PacketRegsitryMixin<ExampleRegistry,ExamplePacket>::registerInterpreter;
- private:
- virtual void v_nextInterpreter() const
- {
- // nextType() is defined in Parse_Example and
- // returns the key in the ExampleRegistry of the
- // next Packet.
- registerInterpreter(nextType(),begin()+header_length, end());
- }
- };
- \endcode
-
- For further details on the packet registry, see
- senf::PacketRegistry.
-
- \section packet_impl Implementation details
-
- The Packet interface is implemented to minimize overhead as
- far as possible without getting to complex. One area for
- improvement is the container class used to hold the raw
- data. This currently is an \a std::vector. This could be
- improved by either allocating some headroom/tailroom in the
- vector and using this when inserting data at the beginning or
- end. Alternatively, a new container class (like the
- senf::deque_list) could be used to support zero-copy
- semantics.
-
- At the moment, we leave the implementation at
- std::vector. This container is very simple and especially it
- can directly be sent out using the operating system since a \a
- vector stores data at contiguous memory locations. An \a
- std::deque could be used with \a writev(), however since we
- have no access to the implementation details of the \a deque,
- we cannot construct the \a writev() data structures.
-
- The interpreter list managed by Packet is lazy, meaning packet
- interpreter facades are added only when requested by next(),
- last() or find_next(). v_nextInterpreter() is called if
- necessary by these methods to complete the interpreter chain.
-
- To implement the automatic memory management, every Packet
- facade is reference counted. Additionally, the number of
- (indirect) references to PacketImpl is counted. This allows to
- manage the PacketImpl instance automatically. To make this
- work, it is necessary to ensure throughout the Packet code,
- that the reference count of a Packet is not accidentally
- decremented to zero. Also, the internal pointers from the
- interpreter list to the Packet facades must not be
- counted. They are therefore implemented differently (
- boost::shared_ptr vs. boost::intrusive_ptr). The choice of
- boost::intrusive_ptr for the externally visible smart pointer
- for all Packet facades is taken to reduce the overhead (an
- intrusive_ptr is only the size of an ordinary pointer, a
- smart_ptr has the size of two pointers).
-
- \nosubgrouping
+ template <class PackeType> class ConcretePacket;
+
+ /** \brief
*/
- class Packet : boost::noncopyable
+ class Packet
+ : public SafeBool<Packet>,
+ public boost::equality_comparable<Packet>
{
public:
- ///\name Types
- ///@{
- typedef boost::uint8_t byte; //!< single byte datatype
- ///@}
-
- private:
- ///\name Implementation
- ///@{
- // These types are implementation details. They are however
- // needed to provide the correct typedefs for the user
- // interface. Hiding these classes would incur a huge
- // additional indirection overhead.
-
- typedef std::vector<byte> raw_container;
- typedef boost::shared_ptr<Packet> interpreter_list_ptr;
- typedef std::list<senf::Packet::interpreter_list_ptr> interpreter_list;
- typedef unsigned refcount_t;
-
- ///@}
-
- public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef void type;
+ typedef senf::detail::packet::iterator iterator;
+ typedef senf::detail::packet::const_iterator const_iterator;
+ typedef senf::detail::packet::size_type size_type;
+ typedef senf::detail::packet::difference_type difference_type;
+ typedef senf::detail::packet::byte byte;
+ typedef PacketInterpreterBase::factory_t factory_t;
+
+ enum NoInit_t { noinit };
///////////////////////////////////////////////////////////////////////////
- ///\name Types
+ ///\name Structors and default members
///@{
- /** \brief smart pointer template for all Packet classes
-
- This struct is just a template typedef. It defines the
- smart pointer used for all Packet classes.
- */
- template <class T> struct ptr_t { typedef boost::intrusive_ptr<T> ptr; };
+ // default copy constructor
+ // default copy assignment
+ // default destructor
+
+ Packet();
+ Packet clone() const;
- /** \brief smart pointer to the Packet facades
+ // conversion constructors
- Every derived class \e must redeclare this member for it's
- derived type:
- \code
- typedef ptr_t<DerivedClass>::ptr ptr
- \endcode
- */
- typedef ptr_t<Packet>::ptr ptr;
- typedef raw_container::iterator iterator; //!< raw data iterator
- typedef raw_container::size_type size_type;
- typedef raw_container::difference_type difference_type;
+ template <class PacketType>
+ Packet(ConcretePacket<PacketType> packet);
///@}
+ ///////////////////////////////////////////////////////////////////////////
- // ////////////////////////////////////////////////////////////////////////
-
- ///\name Creating packets
+ ///\name Interpreter chain access
///@{
- /** \brief create new Packet
+ Packet next() const;
+ template <class OtherPacket> OtherPacket next() const;
+ template <class OtherPacket> OtherPacket next(NoThrow_t) const;
+ template <class OtherPacket> OtherPacket findNext() const;
+ template <class OtherPacket> OtherPacket findNext(NoThrow_t) const;
+
+ Packet prev() const;
+ template <class OtherPacket> OtherPacket prev() const;
+ template <class OtherPacket> OtherPacket prev(NoThrow_t) const;
+ template <class OtherPacket> OtherPacket findPrev() const;
+ template <class OtherPacket> OtherPacket findPrev(NoThrow_t) const;
+
+ Packet first() const;
+ template <class OtherPacket> OtherPacket first() const;
+ template <class OtherPacket> OtherPacket first(NoThrow_t) const;
- This method is used to create a new Packet. All Packet
- instances are created via this method, they are \e never
- created directly from the Packet derived class.
+ Packet last() const;
+ template <class OtherPacket> OtherPacket last() const;
+ template <class OtherPacket> OtherPacket last(NoThrow_t) const;
- \param OtherPacket Type of Packet to create, a Packet
- derived class
- \param b begin iterator of byte range to create the Packet
- from
- \param e corresponding end iterator
- \return smart pointer to new packet
- \throws TruncatedPacketException The data cannot be parsed
- securely (the data might be truncated or just
- plain invalid)
- */
- template <class OtherPacket, class InputIterator>
- static typename ptr_t<OtherPacket>::ptr create(InputIterator b, InputIterator e);
- template <class OtherPacket>
- static typename ptr_t<OtherPacket>::ptr create();
+ template <class OtherPacket> OtherPacket parseNextAs() const;
+ Packet parseNextAs(factory_t factory) const;
+ template <class OtherPacket> bool is() const;
+ template <class OtherPacket> OtherPacket as() const;
- template <class OuterPacket>
- static typename ptr_t<OuterPacket>::ptr create(Packet::ptr payload);
+ Packet append(Packet packet) const;
///@}
- ///\name Interpreter chain
+ ///\name Data access
///@{
- /** \brief get next packet from the interpreter chain
- \return smart pointer to next packet or 0 if last packet */
- ptr next() const;
- /** \brief get previous packet from the interpreter chain
- \return smart pointer to previous packet or 0 if last packet */
- ptr prev() const;
- /** \brief first packet of the interpreter chain
- \return smart pointer to first packet */
- ptr head() const;
- /** \brief get last packet of the interpreter chain
- \return smart pointer to last packet */
- ptr last() const;
-
- /** \brief first packet of given type after the current packet
- \return smart pointer to first following packet of type \a
- OtherPacket or 0, if no such packet exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_next() const;
- /** \brief first packet of given type before the current packet
- \return smart pointer to first preceding packet of type \a
- OtherPacket or 0, if no such packet exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_prev() const;
-
- /** \brief first packet of given type after the current packet
- \return smart pointer to first following packet of type \a
- OtherPacket. \e Assert's, that a packet of this type exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_next() const;
- /** \brief first packet of given type before the current packet
- \return smart pointer to first preceding packet of type \a
- OtherPacket. \e Assert's, that a packet of this type exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_prev() const;
-
- /** \brief check, whether the packet is of the given type
- \return true, if packet is of type \a OtherPacket, false
- otherwise */
- template <class OtherPacket> bool is() const;
- /** \brief cast packet pointer to the given type
- \return a properly cast smart pointer if packet is of type
- \a OtherPacket. Otherwise return 0 */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr as();
-
- /** \brief replace current packet interpreter
-
- This method will \e replace the current packet facade in
- the interpreter list with a new interpreter given by \a
- OtherPacket.
-
- \attention This invalidates the packet instance \e
- this. You must ensure, not to use the Packet instance any
- further after this call
-
- \return smart pointer to a \e new packet facade
- \throws TruncatedPacketException there is not enough data
- to safely interpret the packet as the given type. The
- original packet is \e not invalidated
- */
- template <class OtherPacket>
- typename ptr_t<OtherPacket>::ptr reinterpret();
-
+ PacketData & data() const;
+ size_type size() const;
+
///@}
- ///\name Raw packet data
+ ///\name Other methods
///@{
- /** \brief begin iterator of raw packet data
-
- This iterator allows access to the raw data interpreted by
- the packet facade. This \e includes any header possibly
- interpreted by the derived packet instance. To access the
- payload of the packet, use next()->begin().
-
- \return random access iterator to the begin of the raw
- data */
- iterator begin() const;
- /** \brief past-the-end iterator of raw packet data
-
- This iterator allows access to the raw data interpreted by
- the packet facade. This \e includes any header possibly
- interpreted by the derived packet instance. To access the
- payload of the packet, use next()->end().
-
- \return random access past-the-end iterator of the raw
- data */
- iterator end() const;
- /** \brief raw data size of packet
- \return size of the raw data interpreted by this
- packet in bytes. This is \e not necessarily the size of
- the complete packet, use head()->size() for this. */
- size_t size() const;
-
- // Modifying the raw packet data
-
- typedef enum { AUTO, BEFORE, INSIDE, OUTSIDE, AFTER } Whence;
-
- /** \brief insert single byte \a v before pos
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void insert(iterator pos, byte v, Whence whence = AUTO);
- /** \brief insert \a n copies of byte \a v before pos
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void insert(iterator pos, size_type n, byte v, Whence whence = AUTO);
- /** \brief insert a copy of the given range before pos
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- template <class InputIterator>
- void insert(iterator pos, InputIterator f, InputIterator l, Whence whence = AUTO);
-
- /** \brief erase single byte
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void erase(iterator pos);
- /** \brief erase range
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void erase(iterator first, iterator last);
+ bool operator==(Packet other) const;
+ bool boolean_test() const;
- ///@}
+ void finalize() const;
void dump(std::ostream & os) const;
- protected:
- ///\name Derived class interface
- ///@{
+ TypeIdValue typeId() const;
+ factory_t factory() const;
+
+ ///@}
- /** \brief create new interpreter facade for an existing packet
+ protected:
+ explicit Packet(PacketInterpreterBase::ptr packet);
- This constructor is called, when a new interpreter is to
- be added to the interpreter chain. The constructor is
- called indirectly from registerInterpreter() or
- reinterpret() via the derived classes template
- constructor.
- */
- template <class Operation>
- Packet(Operation const & arg);
- virtual ~Packet();
+ PacketInterpreterBase::ptr ptr() const;
private:
- /** \brief create next packet interpreter
+ Packet checkNext() const;
+ Packet checkLast() const;
+
+ PacketInterpreterBase::ptr packet_;
+
+ template <class PacketType>
+ friend class ConcretePacket;
+ };
- This method is called by next(), last() or find_next() to
- create any missing interpreters in the interpreter
- chain. This method must be overridden in the derived class
- to register the next packet interpreter in the interpreter
- chain with the packet framework.
+ /** \brief
+ */
+ template <class PacketType>
+ class ConcretePacket
+ : public Packet
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef PacketType type;
+ typedef PacketInterpreter<PacketType> interpreter;
- To register the new interpreter, use
- registerInterpreter() to create the new Packet
- instance. The new instance is automatically added to the
- interpreter chain after the current interpreter.
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
- See also senf::PacketRegistryMixin on how to
- use a Registry to find the next interpreters implementing
- class.
- */
- virtual void v_nextInterpreter() const = 0;
+ // default copy constructor
+ // default copy assignment
+ // default destructor
+ // no conversion constructors
- /** \brief finalize packet for sending
+ ConcretePacket();
- This method is called by the packet framework to let the
- interpreter facade do some final calculations/packet
- cleanup before the packet is sent out or digested in some
- other way. This is the place to calculate checksums and
- such.
+ static factory_t factory();
- This method is automatically called for all interpreters on
- the interpreter chain.
- */
- virtual void v_finalize() = 0;
+ // Create completely new packet
- virtual void v_dump(std::ostream & os) const = 0;
+ static ConcretePacket create();
+ static ConcretePacket create(NoInit_t);
+ static ConcretePacket create(size_type size);
+ static ConcretePacket create(size_type size, NoInit_t);
+ template <class ForwardReadableRange>
+ static ConcretePacket create(ForwardReadableRange const & range);
- protected:
- /** \brief add interpreter to interpreter chain
-
- This method is used by v_nextInterpreter() in the derived
- classes to add a new interpreter to the interpreter
- chain. This method will call \c OtherPacket's constructor
- with the correct arguments and insert the new interpreter
- into the interpreter list. This method is used, if no
- further arguments are to be passed to the \c OtherPacket
- constructor. If additional arguments are necessary, just
- add them after \c end. The compiler will then choose the
- correct overload to use.
- */
- template <class OtherPacket>
- typename ptr_t<OtherPacket>::ptr registerInterpreter(
- raw_container::iterator begin, raw_container::iterator end) const;
- template <class OtherPacket, class A0>
- typename ptr_t<OtherPacket>::ptr registerInterpreter(
- raw_container::iterator begin, raw_container::iterator end,
- A0 const & a0) const;
-
-# define BOOST_PP_ITERATION_PARAMS_1 (4, (2, 9, "Packets/Packet.mpp", 3))
-# include BOOST_PP_ITERATE()
+ // Create packet as new packet after a given packet
- ///@}
+ static ConcretePacket createAfter(Packet packet);
+ static ConcretePacket createAfter(Packet packet, NoInit_t);
+ static ConcretePacket createAfter(Packet packet, size_type size);
+ static ConcretePacket createAfter(Packet packet, size_type size, NoInit_t);
+ template <class ForwardReadableRange>
+ static ConcretePacket createAfter(Packet packet,
+ ForwardReadableRange const & range);
- private:
+ // Create packet as new packet (header) before a given packet
- ///\name Implementation
- ///@{
-
- void add_ref() const;
- bool release();
- bool unlink();
-
- struct PacketOp_register;
- friend class PacketOp_register;
- void i_registerInterpreter(Packet * p) const;
+ static ConcretePacket createBefore(Packet packet);
+ static ConcretePacket createBefore(Packet packet, NoInit_t);
- struct PacketOp_replace;
- friend class PacketOp_replace;
- void i_replaceInterpreter(Packet * p);
+ // Create a clone of the current packet
- struct PacketOp_set;
- friend class PacketOp_set;
- void i_setInterpreter(impl::PacketImpl * i);
+ ConcretePacket clone() const;
- private:
- friend class impl::PacketImpl;
- template <class OtherPacket> friend class impl::PkReg_EntryImpl;
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
- impl::PacketImpl* impl_;
- size_type begin_;
- size_type end_;
- interpreter_list::iterator self_;
- mutable bool parsed_;
- mutable refcount_t refcount_;
+ // Field access
- ///@}
- };
+ typename interpreter::parser * operator->() const;
- /** \brief dump packet to stream
- \related Packet */
- // std::ostream & operator<<(std::ostream & os, Packet const & packet);
+ protected:
- /** \brief smart pointer handling
- \relates Packet */
- void intrusive_ptr_add_ref(Packet const *);
- /** \brief smart pointer handling
- \relates Packet */
- void intrusive_ptr_release(Packet *);
+ private:
+ ConcretePacket(typename interpreter::ptr packet_);
+
+ typename interpreter::ptr ptr() const;
- struct TruncatedPacketException : public std::exception
- { virtual char const * what() const throw() { return "truncated packet"; } };
+ friend class Packet;
+ friend class PacketInterpreter<PacketType>;
+ };
}
-// ////////////////////////////hh.e////////////////////////////////////////
+///////////////////////////////hh.e////////////////////////////////////////
#include "Packet.cci"
#include "Packet.ct"
#include "Packet.cti"
-
-#include "Packet.mpp"
#endif
\f
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef IH_Packet_
-#define IH_Packet_ 1
-
-// Custom includes
-
-///////////////////////////////ih.p////////////////////////////////////////
-
-#ifdef SATCOM_PKF_REFC_DEBUG
-#include <iostream>
-#define SATCOM_PKF_REFC_MSG(x) std::cerr << x
-#else
-#define SATCOM_PKF_REFC_MSG(x)
-#endif
-
-namespace senf {
-
-namespace impl {
-
- // This deleter is used in the PacketImpl list holding the
- // Packet's. It only decrements the Packet refcount. If this
- // drops to 0 (i.e. the packet is removed from the list and no
- // external reference exists) the packet ist deleted.
- //
- // Since this is called, when the packet is removed from the
- // list, we set the impl_ member to 0 to mark, that the packet
- // is now orphaned and every use should throw an exception ...
- //
- // To make this work we must make sure, that the packet
- // refcount is incremented when we add the packet to the list.
- struct ListPacketDeleter {
- void operator()(Packet * p);
- };
-
- struct PacketImpl
- {
- Packet::raw_container data_;
- Packet::interpreter_list interpreters_;
- Packet::refcount_t refcount_;
-
- PacketImpl();
- PacketImpl(unsigned size, Packet::byte initValue);
- ~PacketImpl();
- template <class InputIterator>
- PacketImpl(InputIterator begin, InputIterator end);
-
- void add_ref();
- bool release();
-
- Packet::interpreter_list::iterator appendInterpreter(Packet * p);
- Packet::interpreter_list::iterator prependInterpreter(Packet * p);
- bool releaseInterpreter(Packet * p);
- void truncateInterpreters(Packet const * p);
- void truncateInterpretersAfter(Packet const * p);
-
- void updateIterators(Packet::size_type index, Packet::difference_type n,
- Packet::interpreter_list::iterator self,
- Packet::Whence whence);
-
- ///////////////////////////////////////////////////////////////////////////
- // These are here to simplify the friend declaration in Packet
-
- static void packet_add_ref(Packet const * p);
- static void packet_release(Packet * p);
- static PacketImpl* impl(Packet const * p);
- static Packet::interpreter_list::iterator self(Packet const * p);
- };
-
- // These methods are used internally to keep PacketImpl_ alive during
- // method invocations
- void intrusive_ptr_add_ref(PacketImpl * p);
- void intrusive_ptr_release(PacketImpl * p);
-}}
-
-
-struct senf::Packet::PacketOp_register
-{
- size_type b;
- size_type e;
- const Packet * p;
-
- PacketOp_register(size_type b_, size_type e_, const Packet * p_)
- : b(b_), e(e_), p(p_) {}
-
- size_type begin() const { return b; }
- size_type end() const { return e; }
- void operator ()(Packet * self) const
- { p->i_registerInterpreter(self); }
-};
-
-struct senf::Packet::PacketOp_replace
-{
- Packet * p;
-
- PacketOp_replace(Packet * p_) : p(p_) {}
-
- size_type begin() const { return p->begin_; }
- size_type end() const { return p->end_; }
- void operator()(Packet * self) const
- { p->i_replaceInterpreter(self); }
-};
-
-struct senf::Packet::PacketOp_set
-{
- impl::PacketImpl * i;
-
- PacketOp_set(impl::PacketImpl * i_) : i(i_) {}
-
- size_type begin() const { return 0; }
- size_type end() const { return i->data_.size(); }
- void operator()(Packet * self) const
- { self->i_setInterpreter(i); }
-};
-
-///////////////////////////////ih.e////////////////////////////////////////
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#if !BOOST_PP_IS_ITERATING
-
-// Custom includes
-#include <boost/preprocessor/iteration/iterate.hpp>
-#include <boost/preprocessor/enum.hpp>
-#include <boost/preprocessor/cat.hpp>
-
-# ifndef MPP_Packet_
-# define MPP_Packet_
-# define pkARG(z,n,data) BOOST_PP_CAT(A,n) const & BOOST_PP_CAT(a,n)
-# else
-# undef pkARG
-# endif
-
-#else
-//////////////////////////////mpp.p////////////////////////////////////////
-
-#if BOOST_PP_ITERATION_DEPTH()==1 && BOOST_PP_ITERATION_FLAGS()==1
-///////////////////////////////////////////////////////////////////////////
-// Packet::reinterpret member template declaration
-
-template < class OtherPacket, BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A) >
-typename ptr_t<OtherPacket>::ptr reinterpret( BOOST_PP_ENUM( BOOST_PP_ITERATION(), pkARG, ) );
-
-#elif BOOST_PP_ITERATION_DEPTH()==1 && BOOST_PP_ITERATION_FLAGS()==2
-///////////////////////////////////////////////////////////////////////////
-// Packet::reinterpret implementation
-
-template <class OtherPacket, BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A) >
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr
-senf::Packet::reinterpret( BOOST_PP_ENUM( BOOST_PP_ITERATION(), pkARG, ) )
-{
- if (!OtherPacket::check(begin(),end()))
- throw TruncatedPacketException();
- typename ptr_t<OtherPacket>::ptr p (
- new OtherPacket(PacketOp_replace(this),
- BOOST_PP_ENUM_PARAMS( BOOST_PP_ITERATION(), a ) ),
- false);
- return p;
-}
-
-#elif BOOST_PP_ITERATION_DEPTH()==1 && BOOST_PP_ITERATION_FLAGS()==3
-///////////////////////////////////////////////////////////////////////////
-// Packet::registerInterpreter member template declaration
-
-template < class OtherPacket, BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A) >
-typename ptr_t<OtherPacket>::ptr registerInterpreter(
- raw_container::iterator begin, raw_container::iterator end,
- BOOST_PP_ENUM( BOOST_PP_ITERATION(), pkARG, ) ) const;
-
-#elif BOOST_PP_ITERATION_DEPTH()==1 && BOOST_PP_ITERATION_FLAGS()==4
-///////////////////////////////////////////////////////////////////////////
-// Packet::registerIterpreter implementation
-
-template <class OtherPacket, BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A) >
-prefix_ typename senf::Packet::ptr_t<OtherPacket>::ptr
-senf::Packet::registerInterpreter(raw_container::iterator begin,
- raw_container::iterator end,
- BOOST_PP_ENUM( BOOST_PP_ITERATION(), pkARG, ) )
- const
-{
- if (!OtherPacket::check(begin,end))
- throw TruncatedPacketException();
- typename ptr_t<OtherPacket>::ptr p (
- new OtherPacket(PacketOp_register(begin-impl_->data_.begin(),
- end-impl_->data_.begin(),
- this),
- BOOST_PP_ENUM_PARAMS( BOOST_PP_ITERATION(), a) ),
- false);
- return p;
-}
-
-#elif BOOST_PP_ITERATION_DEPTH()==1 && BOOST_PP_ITERATION_FLAGS()==5
-///////////////////////////////////////////////////////////////////////////
-// Packet::create declaration
-
-template < class OtherPacket, class InputIterator,
- BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A) >
-static typename senf::Packet::ptr_t<OtherPacket>::ptr create(
- InputIterator b, InputIterator e,
- BOOST_PP_ENUM( BOOST_PP_ITERATION(), pkARG, ) );
-
-#elif BOOST_PP_ITERATION_DEPTH()==1 && BOOST_PP_ITERATION_FLAGS()==6
-///////////////////////////////////////////////////////////////////////////
-// Packet::create implementation
-
-template < class OtherPacket, class InputIterator,
- BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A) >
-typename senf::Packet::ptr_t<OtherPacket>::ptr senf::Packet::create(
- InputIterator b, InputIterator e,
- BOOST_PP_ENUM( BOOST_PP_ITERATION(), pkARG, ) )
-{
- boost::intrusive_ptr<impl::PacketImpl> impl (new impl::PacketImpl(b,e),false);
- if (!OtherPacket::check(impl->data_.begin(), impl->data_.end()))
- throw TruncatedPacketException();
- typename ptr_t<OtherPacket>::ptr p (
- new OtherPacket(PacketOp_set(impl.get()),
- BOOST_PP_ENUM_PARAMS( BOOST_PP_ITERATION(), a) ),
- false);
- return p;
-}
-
-#endif
-
-//////////////////////////////mpp.e////////////////////////////////////////
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Unit tests
+/** \file
+ \brief Packet.test unit tests */
//#include "Packet.test.hh"
//#include "Packet.test.ih"
// Custom includes
+#include <sstream>
+#include "PacketType.hh"
+#include "PacketRegistry.hh"
#include "Packet.hh"
+#include "ParseInt.hh"
+#include "PacketParser.hh"
#include "DataPacket.hh"
-#include "GenericPacket.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
-
-// Since Packet is abstract, we can only test the Packet interface using
-// a simple implementation: DataPacket and GenericPacket.
-
namespace {
- Packet::byte data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };
+ struct RegTag {
+ typedef unsigned key_t;
+ };
- bool compare(Packet::iterator b, Packet::iterator e, unsigned o=0)
+ struct FooPacketType
+ : public senf::PacketTypeBase,
+ public senf::PacketTypeMixin<FooPacketType>
{
- unsigned i (o);
- for (; b!=e; ++b, ++i)
- if (i>=sizeof(data) || *b != data[i])
- return false;
- return true;
+ using senf::PacketTypeMixin<FooPacketType>::nextPacketRange;
+ using senf::PacketTypeMixin<FooPacketType>::initSize;
+ using senf::PacketTypeMixin<FooPacketType>::init;
+ typedef senf::PacketInterpreter<FooPacketType> interpreter;
+ static interpreter::size_type initSize()
+ { return 4u; }
+ };
+ typedef senf::ConcretePacket<FooPacketType> FooPacket;
+
+ struct BarPacketParser : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(BarPacketParser);
+
+ typedef senf::Parse_UInt16 Parse_Type;
+ typedef senf::Parse_Int32 Parse_Length;
+ typedef senf::Parse_UInt16 Parse_Reserved;
+
+ Parse_Type type() const { return parse<Parse_Type> (i()); }
+ Parse_Length length() const { return parse<Parse_Length> (i()+2); }
+ Parse_Reserved reserved() const { return parse<Parse_Reserved> (i()+6); }
+ };
+
+ struct BarPacketType
+ : public senf::PacketTypeBase,
+ public senf::PacketTypeMixin<BarPacketType,RegTag>
+ {
+ typedef senf::PacketTypeMixin<BarPacketType,RegTag> mixin;
+ typedef senf::ConcretePacket<BarPacketType> packet;
+ typedef BarPacketParser parser;
+ using mixin::nextPacketRange;
+ using mixin::nextPacketType;
+ using mixin::initSize;
+ using mixin::init;
+ static size_type initSize()
+ { return 8u; }
+ static void init(packet p) {
+ p->reserved() = 0xA0A0u;
+ }
+ static void dump(packet p, std::ostream & os) {
+ os << "BarPacket:\n"
+ << "type: " << p->type() << "\n"
+ << "length: " << p->length() << "\n";
+ }
+ static void finalize(packet p) {
+ if (p.next())
+ p->type() = senf::PacketRegistry<RegTag>::key(p.next());
+ else
+ p->type() = -1;
+ }
+ static registry_key_t nextPacketKey(packet p) {
+ return p->type();
+ }
+ };
+ typedef BarPacketType::packet BarPacket;
+
+ namespace reg {
+ senf::PacketRegistry<RegTag>::RegistrationProxy<FooPacketType> registerFoo(1u);
+ senf::PacketRegistry<RegTag>::RegistrationProxy<BarPacketType> registerBar(2u);
}
}
-BOOST_AUTO_UNIT_TEST(Packet_DataPacket)
-{
- Packet::ptr p (Packet::create<DataPacket>(data, data+sizeof(data)));
-
- BOOST_REQUIRE( p );
- BOOST_CHECK_EQUAL( p->size(), sizeof(data) );
- BOOST_CHECK( compare(p->begin(), p->end()) );
-
- *p->begin() = 20;
- BOOST_CHECK( !compare(p->begin(), p->end()) );
- BOOST_CHECK_EQUAL( *p->begin(), 20 );
-
- BOOST_CHECK( !p->next() );
- BOOST_CHECK( !p->prev() );
- BOOST_CHECK_EQUAL( p->head(), p );
- BOOST_CHECK_EQUAL( p->last(), p );
-
- BOOST_CHECK( p->is<DataPacket>() );
- BOOST_CHECK( p->as<DataPacket>() );
-}
-
-BOOST_AUTO_UNIT_TEST(Packet_GenericPacket)
-{
- GenericPacket<4,6>::ptr p (Packet::create< GenericPacket<4,6> >(data, data+sizeof(data)));
-
- // check, that the packet was constructed corretly
- BOOST_REQUIRE( p );
- BOOST_CHECK_EQUAL( p->size(), sizeof(data) );
- BOOST_CHECK( compare(p->begin(), p->end()) );
- BOOST_CHECK_EQUAL( p->header_len(), 4u );
- BOOST_CHECK( compare(p->begin_header(), p->end_header()) );
- BOOST_CHECK_EQUAL( p->trailer_len(), 6u );
- BOOST_CHECK( compare(p->begin_trailer(), p->end_trailer(), sizeof(data)-6) );
-
- // check the first packet in the interpreter chain
- BOOST_CHECK_EQUAL( p->head(), p );
- BOOST_CHECK( !p->prev() );
- BOOST_CHECK(( p->is< GenericPacket<4,6> >() ));
- BOOST_CHECK( !p->is<DataPacket>() );
- BOOST_CHECK(( !p->is< GenericPacket<4,4> >() ));
- BOOST_CHECK(( p->as< GenericPacket<4,6> >() ));
- BOOST_CHECK( !p->as<DataPacket>() );
-
- // check the next packet in the interpreter chain
- BOOST_REQUIRE( p->next() );
- BOOST_CHECK( p->next()->is<DataPacket>() );
- BOOST_CHECK(( !p->next()->is< GenericPacket<4,6> >() ));
-
- // check the contents of the second interpreter
- BOOST_CHECK_EQUAL( p->next()->size(), sizeof(data)-10 );
- BOOST_CHECK( compare(p->next()->begin(), p->next()->end(), 4) );
-
- // validate, that the two interpreters share the same data
- // container
- *p->next()->begin() = 20;
- BOOST_CHECK( !compare(p->next()->begin(), p->next()->end(), 4) );
- BOOST_CHECK( *p->next()->begin() == 20 );
- BOOST_CHECK( !compare(p->begin(), p->end()) );
- BOOST_CHECK( *(p->begin()+4) == 20 );
-
- // We need require here. If this fails, p->last() will probably
- // run into an endless loop ...
- BOOST_REQUIRE( !p->next()->next() );
- BOOST_CHECK_EQUAL( p->next(), p->last() );
-}
-
-BOOST_AUTO_UNIT_TEST(Packet_Reinterpret)
-{
- Packet::ptr p (Packet::create< GenericPacket<4,4> >(data, data+sizeof(data)));
-
- BOOST_CHECK( p->next()->is<DataPacket>() );
- p->next()->reinterpret< GenericPacket<6> >();
- BOOST_CHECK( p->next()->is< GenericPacket<6> >() );
- BOOST_REQUIRE( p->next()->next() );
- BOOST_CHECK( p->next()->next()->is<DataPacket>() );
- BOOST_CHECK( !p->next()->next()->next() );
-
- BOOST_CHECK_EQUAL( p->next()->next()->size(), sizeof(data)-14 );
- BOOST_CHECK( compare(p->next()->next()->begin(),
- p->next()->next()->end(), 10) );
-
- p = p->reinterpret< GenericPacket<8,2> >();
- BOOST_REQUIRE( p->next() );
- BOOST_CHECK( p->next()->is<DataPacket>() );
-
- BOOST_CHECK_EQUAL( p->next()->size(), sizeof(data)-10 );
- BOOST_CHECK( compare(p->next()->begin(), p->next()->end(), 8) );
-}
-
-BOOST_AUTO_UNIT_TEST(Packet_InsertErase)
+BOOST_AUTO_UNIT_TEST(packet)
{
- Packet::ptr p (Packet::create< GenericPacket<7,3> >(data, data+sizeof(data)));
- p->next()->reinterpret< GenericPacket<4> >();
-
- BOOST_CHECK_EQUAL( p->size(), 20u );
- BOOST_CHECK_EQUAL( p->next()->size(), 10u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 6u );
-
- BOOST_CHECK_EQUAL( p->next()->next()->begin()[0], 11 );
- BOOST_CHECK_EQUAL( p->end()[-1], 19 );
- BOOST_CHECK_EQUAL( p->next()->end()[-1], 16 );
- BOOST_CHECK_EQUAL( p->next()->next()->end()[-1], 16 );
-
- p->next()->insert(p->next()->begin()+2, data, data+6);
-
- BOOST_CHECK_EQUAL( p->size(), 26u );
- BOOST_CHECK_EQUAL( p->next()->size(), 16u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 6u );
-
- BOOST_CHECK( compare(p->begin(), p->begin()+9) );
- BOOST_CHECK( compare(p->begin()+9, p->begin()+15) );
- BOOST_CHECK( compare(p->begin()+15, p->end(), 9) );
- BOOST_CHECK( compare(p->next()->begin(), p->next()->begin()+2, 7) );
- BOOST_CHECK( compare(p->next()->begin()+2, p->next()->begin()+8) );
- BOOST_CHECK( compare(p->next()->begin()+8, p->next()->end(), 9) );
- BOOST_CHECK( compare(p->next()->next()->begin(), p->next()->next()->end(), 11) );
-
- p->next()->erase( p->next()->begin()+2, p->next()->begin()+8 );
-
- BOOST_CHECK_EQUAL( p->size(), 20u );
- BOOST_CHECK_EQUAL( p->next()->size(), 10u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 6u );
-
- BOOST_CHECK( compare(p->begin(), p->end()) );
- BOOST_CHECK( compare(p->next()->begin(), p->next()->end(), 7) );
- BOOST_CHECK( compare(p->next()->next()->begin(), p->next()->next()->end(), 11) );
-
- p->next()->insert(p->next()->begin()+4, data, data+2);
-
- BOOST_CHECK_EQUAL( p->size(), 22u );
- BOOST_CHECK_EQUAL( p->next()->size(), 12u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 6u );
-
- BOOST_CHECK( compare(p->next()->next()->begin(), p->next()->next()->end(), 11) );
-
- p->next()->erase(p->next()->begin()+4, p->next()->begin()+6);
-
- BOOST_CHECK_EQUAL( p->size(), 20u );
- BOOST_CHECK_EQUAL( p->next()->size(), 10u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 6u );
-
- BOOST_CHECK( compare(p->begin(), p->end()) );
- BOOST_CHECK( compare(p->next()->begin(), p->next()->end(), 7) );
- BOOST_CHECK( compare(p->next()->next()->begin(), p->next()->next()->end(), 11) );
-
- p->next()->next()->insert(p->next()->begin()+5, data, data+4);
-
- BOOST_CHECK_EQUAL( p->size(), 24u );
- BOOST_CHECK_EQUAL( p->next()->size(), 14u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 10u );
-
- BOOST_CHECK( compare(p->next()->next()->begin(), p->next()->next()->begin()+1, 11) );
- BOOST_CHECK( compare(p->next()->next()->begin()+1, p->next()->next()->begin()+5) );
- BOOST_CHECK( compare(p->next()->next()->begin()+5, p->end(), 12) );
-
- p->next()->erase(p->next()->begin()+3, p->next()->begin()+9);
-
- BOOST_CHECK_EQUAL( p->size(), 18u );
- BOOST_CHECK_EQUAL( p->next()->size(), 8u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 5u );
-
- BOOST_CHECK( compare(p->next()->next()->begin(), p->next()->next()->end(), 12) );
- BOOST_CHECK( compare(p->begin(), p->begin()+10) );
- BOOST_CHECK( compare(p->begin()+10, p->end(), 12) );
-
- p->erase(p->begin()+5, p->end());
-
- BOOST_CHECK_EQUAL( p->size(), 5u );
- BOOST_CHECK_EQUAL( p->next()->size(), 0u );
- BOOST_CHECK_EQUAL( p->next()->next()->size(), 0u );
+ senf::Packet packet (FooPacket::create());
+ BarPacket::createAfter(packet);
+
+ BOOST_REQUIRE( packet );
+ BOOST_CHECK( packet.next() );
+ BOOST_CHECK( ! packet.next().next() );
+ BOOST_CHECK( ! packet.prev() );
+ BOOST_CHECK( packet.next().prev() == packet );
+ BOOST_CHECK( packet.next() != packet );
+ BOOST_CHECK_EQUAL( packet.size(), 12u );
+ BOOST_CHECK_EQUAL( packet.next().size(), 8u );
+ BOOST_CHECK( packet.is<FooPacket>() );
+ BOOST_CHECK( packet.next().is<BarPacket>() );
+ BOOST_CHECK( packet.first() == packet );
+ BOOST_CHECK( packet.last() == packet.next() );
+
+ senf::Packet p2 (packet.next());
+ BOOST_CHECK( p2 );
+ packet.parseNextAs<FooPacket>();
+ BOOST_CHECK_EQUAL( packet.size(), 12u );
+ BOOST_CHECK_EQUAL( packet.next().size(), 8u );
+ BOOST_CHECK( packet.next().is<FooPacket>() );
+ BOOST_CHECK( ! p2 );
+ BOOST_CHECK( packet.next().as<FooPacket>() );
+
+ p2 = packet.next().clone();
+ BOOST_REQUIRE( p2 );
+ packet.next().append( p2 );
+ BOOST_REQUIRE( packet.next().next() );
+ BOOST_CHECK( packet.next().next().next() );
+ BOOST_CHECK( packet.next().next().next().is<senf::DataPacket>() );
+ BOOST_CHECK_EQUAL( packet.size(), 16u );
+
+ // This calls and checks typeId()
+ BOOST_CHECK_EQUAL( senf::PacketRegistry<RegTag>::key(packet), 1u );
+ packet.next().parseNextAs( senf::PacketRegistry<RegTag>::lookup(2u).factory() );
+ BOOST_CHECK( packet.next().next().is<BarPacket>() );
+
+ std::stringstream s;
+ packet.dump(s);
+ BOOST_CHECK_EQUAL( s.str(), "BarPacket:\ntype: 0\nlength: 0\n" );
+
+ packet.finalize();
+ BOOST_CHECK_EQUAL( packet.last().as<BarPacket>()->type(),
+ BarPacket::type::parser::Parse_Type::value_type(-1) );
+ packet.last().append(FooPacket::create());
+ packet.finalize();
+ BOOST_CHECK_EQUAL( packet.next<BarPacket>()->type(), 1u );
+
+ BOOST_CHECK( packet.factory() == FooPacket::factory() );
+
+ senf::Packet::byte data[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x81, 0x82, 0x83 };
+
+ BarPacket::createAfter(packet,data);
+ BOOST_REQUIRE( packet.next() );
+ BOOST_REQUIRE( packet.next().is<BarPacket>() );
+ BOOST_CHECK( packet.last().is<FooPacket>() );
+ BOOST_CHECK_EQUAL( packet.last<BarPacket>()->type(), 1u );
+ BOOST_CHECK_EQUAL( packet.next().size(), 11u );
+ BOOST_REQUIRE( packet.next().next() );
+ BOOST_CHECK( packet.next().next().is<FooPacket>() );
+ BOOST_CHECK( ! packet.next().next().next() );
+ BOOST_CHECK_EQUAL( packet.next().next().data()[0], 0x81u );
+
+ BOOST_CHECK( packet.first<FooPacket>() == packet );
+ BOOST_CHECK( packet.first<FooPacket>(senf::nothrow) == packet );
+ BOOST_CHECK( packet.last<BarPacket>() == packet.last().prev() );
+ BOOST_CHECK( packet.last<BarPacket>(senf::nothrow) == packet.last().prev() );
+ BOOST_CHECK( packet.findNext<FooPacket>() == packet );
+ BOOST_CHECK( packet.findNext<FooPacket>(senf::nothrow) == packet );
+ BOOST_CHECK( packet.last().findPrev<FooPacket>() == packet.last() );
+ BOOST_CHECK( packet.last().findPrev<FooPacket>(senf::nothrow) == packet.last() );
+ BOOST_CHECK( packet.next<BarPacket>() == packet.next() );
+ BOOST_CHECK( packet.next<BarPacket>(senf::nothrow) == packet.next() );
+ BOOST_CHECK( packet.last().prev<FooPacket>() == packet );
+ BOOST_CHECK( packet.last().prev<FooPacket>(senf::nothrow) == packet );
}
-BOOST_AUTO_UNIT_TEST(Packet_new)
+BOOST_AUTO_UNIT_TEST(concretePacket)
{
- Packet::ptr p (Packet::create< GenericPacket<10,4> >());
- BOOST_CHECK_EQUAL(p->size(), 14u);
- Packet::ptr p2 (Packet::create< GenericPacket<2,2> >(p));
- BOOST_CHECK_EQUAL(p2->size(),18u);
+ FooPacket::byte data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+
+ BOOST_CHECK_EQUAL( FooPacket::create().size(), 4u );
+ BOOST_CHECK_EQUAL( FooPacket::create(FooPacket::noinit).size(), 0u );
+ BOOST_CHECK_THROW( FooPacket::create(2u), senf::TruncatedPacketException );
+ BOOST_CHECK_EQUAL( FooPacket::create(10u).size(), 10u );
+ BOOST_CHECK_EQUAL( FooPacket::create(2u,FooPacket::noinit).size(), 2u );
+ BOOST_CHECK_EQUAL( FooPacket::create(data).size(), 6u );
+
+ senf::Packet packet (FooPacket::create());
+
+ BOOST_CHECK_EQUAL( FooPacket::createAfter(packet).size(), 4u );
+ BOOST_CHECK_EQUAL( packet.size(), 8u );
+
+ BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,FooPacket::noinit).size(), 0u );
+ BOOST_CHECK_EQUAL( packet.size(), 4u );
+
+ BOOST_CHECK_THROW( FooPacket::createAfter(packet,2u), senf::TruncatedPacketException );
+ BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,10u).size(), 10u );
+ BOOST_CHECK_EQUAL( packet.size(), 14u );
+
+ BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,2u,FooPacket::noinit).size(), 2u );
+ BOOST_CHECK_EQUAL( packet.size(), 6u );
+
+ BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,data).size(), 6u );
+ BOOST_CHECK_EQUAL( packet.size(), 10u );
+
+ BOOST_CHECK_EQUAL( FooPacket::createBefore(packet).size(), 14u );
+ BOOST_CHECK_EQUAL( packet.size(), 10u );
+
+ BOOST_CHECK_EQUAL( FooPacket::createBefore(packet,FooPacket::noinit).size(), 10u );
+ BOOST_CHECK_EQUAL( packet.size(), 10u );
+
+ BOOST_CHECK( packet.clone() != packet );
+ BOOST_CHECK_EQUAL( BarPacket::create()->reserved(), 0xA0A0u );
}
///////////////////////////////cc.e////////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline non-template functions
+/** \file
+ \brief PacketData non-inline non-template implementation */
-#include "DataPacket.hh"
-//#include "DataPacket.ih"
+#include "PacketData.hh"
+//#include "PacketData.ih"
// Custom includes
+#include "PacketImpl.hh"
+//#include "PacketData.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-prefix_ void senf::DataPacket::v_nextInterpreter()
- const
-{}
-
-prefix_ void senf::DataPacket::v_finalize()
-{}
+// Modifying the raw packet data
-prefix_ void senf::DataPacket::v_dump(std::ostream & os)
- const
+prefix_ void senf::PacketData::resize(size_type n, byte v)
{
- os << "Payload:\n"
- << " size : " << size() << "\n";
+ if (n<size())
+ impl().erase(this,boost::next(begin(),n),end());
+ else if (n>size())
+ impl().insert(this,end(),n-size(),v);
}
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
+//#include "PacketData.mpp"
\f
// Local Variables:
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketData inline non-template implementation */
+
+// Custom includes
+#include <iterator>
+#include "PacketImpl.hh"
+#include "PacketParser.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketData
+
+prefix_ senf::PacketData::iterator senf::PacketData::begin()
+ const
+{
+ BOOST_ASSERT(begin_ <= impl().size());
+ return boost::next(impl().begin(),begin_);
+}
+
+prefix_ senf::PacketData::iterator senf::PacketData::end()
+ const
+{
+ BOOST_ASSERT(end_ <= impl().size());
+ return boost::next(impl().begin(),end_);
+}
+
+prefix_ senf::PacketData::size_type senf::PacketData::size()
+ const
+{
+ return end_ - begin_;
+}
+
+prefix_ bool senf::PacketData::empty()
+ const
+{
+ return begin_ == end_;
+}
+
+prefix_ senf::PacketData::byte senf::PacketData::operator[](size_type n)
+ const
+{
+ BOOST_ASSERT( n < size() );
+ return *( boost::next(begin(),n) );
+}
+
+prefix_ senf::PacketData::byte & senf::PacketData::operator[](size_type n)
+{
+ BOOST_ASSERT( n < size() );
+ return *( boost::next(begin(),n) );
+}
+
+// Modifying the raw packet data
+
+prefix_ void senf::PacketData::insert(iterator pos, byte v)
+{
+ impl().insert(this,pos,v);
+}
+
+prefix_ void senf::PacketData::insert(iterator pos, size_type n, byte v)
+{
+ impl().insert(this,pos,n,v);
+}
+
+prefix_ void senf::PacketData::erase(iterator pos)
+{
+ impl().erase(this,pos);
+}
+
+prefix_ void senf::PacketData::erase(iterator first, iterator last)
+{
+ impl().erase(this,first,last);
+}
+
+prefix_ void senf::PacketData::clear()
+{
+ impl().clear(this);
+}
+
+prefix_ bool senf::PacketData::valid()
+{
+ return impl_;
+}
+
+// protected members
+
+prefix_ senf::PacketData::PacketData(size_type b, size_type e)
+ : impl_(), begin_(b), end_(e)
+{}
+
+prefix_ senf::detail::PacketImpl & senf::PacketData::impl()
+ const
+{
+ BOOST_ASSERT( impl_ );
+ return *impl_;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::safe_data_iterator
+
+prefix_ senf::safe_data_iterator::safe_data_iterator()
+ : data_(0), i_(0)
+{}
+
+prefix_ senf::safe_data_iterator::safe_data_iterator(PacketData & data)
+ : data_(&data), i_(0)
+{}
+
+prefix_ senf::safe_data_iterator::safe_data_iterator(PacketData & data, PacketData::iterator i)
+ : data_(&data), i_(std::distance(data.begin(),i))
+{}
+
+prefix_ senf::safe_data_iterator::safe_data_iterator(PacketParserBase const & parser)
+ : data_(&parser.data()), i_(std::distance(data_->begin(),parser.i()))
+{}
+
+prefix_ senf::safe_data_iterator & senf::safe_data_iterator::operator=(PacketData::iterator i)
+{
+ BOOST_ASSERT(data_);
+ i_ = std::distance(data_->begin(),i);
+ return *this;
+}
+
+prefix_ senf::safe_data_iterator &
+senf::safe_data_iterator::operator=(PacketParserBase const & parser)
+{
+ data_ = &parser.data();
+ i_ = std::distance(data_->begin(),parser.i());
+ return *this;
+}
+
+prefix_ senf::safe_data_iterator::operator senf::PacketData::iterator()
+ const
+{
+ return i();
+}
+
+prefix_ bool senf::safe_data_iterator::boolean_test()
+ const
+{
+ return data_;
+}
+
+prefix_ senf::PacketData & senf::safe_data_iterator::data()
+ const
+{
+ BOOST_ASSERT(data_);
+ return *data_;
+}
+
+prefix_ senf::safe_data_iterator::value_type & senf::safe_data_iterator::dereference()
+ const
+{
+ return *i();
+}
+
+prefix_ bool senf::safe_data_iterator::equal(safe_data_iterator const & other)
+ const
+{
+ BOOST_ASSERT(data_ == other.data_);
+ return i_ == other.i_;
+}
+
+prefix_ senf::safe_data_iterator::difference_type
+senf::safe_data_iterator::distance_to(safe_data_iterator const & other)
+ const
+{
+ BOOST_ASSERT(data_ == other.data_);
+ return other.i_ - i_;
+}
+
+prefix_ void senf::safe_data_iterator::increment()
+{
+ ++i_;
+}
+
+prefix_ void senf::safe_data_iterator::decrement()
+{
+ BOOST_ASSERT(i_>0);
+ --i_;
+}
+
+prefix_ void senf::safe_data_iterator::advance(difference_type n)
+{
+ BOOST_ASSERT( -n < difference_type(i_) );
+ i_ += n;
+}
+
+prefix_ senf::PacketData::iterator senf::safe_data_iterator::i()
+ const
+{
+ BOOST_ASSERT(data_);
+ return boost::next(data_->begin(),i_);
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
-// Copyright (C) 2007
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
// Stefan Bund <g0dil@berlios.de>
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief IpV6Packet inline template implementation */
+ \brief PacketData inline template implementation */
-//#include "IpV6Packet.ih"
+//#include "PacketData.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <class Arg>
-prefix_ senf::IpV6Packet::IpV6Packet(Arg const & arg)
- : Packet(arg)
-{}
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketData
+
+// Modifying the raw packet data
+
+template <class InputIterator>
+prefix_ void senf::PacketData::
+insert(iterator pos, InputIterator f, InputIterator l,
+ typename boost::disable_if< boost::is_convertible<InputIterator,size_type> >::type *)
+{
+ impl().insert(this,pos,f,l);
+}
///////////////////////////////cti.e///////////////////////////////////////
#undef prefix_
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketData public header */
+
+#ifndef HH_PacketData_
+#define HH_PacketData_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+#include <boost/type_traits.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include "Utils/SafeBool.hh"
+#include "PacketTypes.hh"
+
+//#include "PacketData.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ /** \brief
+
+ PacketData only exists to separate out the container interface from PacketInterpreter.
+ */
+ class PacketData
+ : boost::noncopyable
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef senf::detail::packet::smart_pointer<PacketData>::ptr_t ptr;
+
+ typedef senf::detail::packet::iterator iterator;
+ typedef senf::detail::packet::const_iterator const_iterator;
+ typedef senf::detail::packet::size_type size_type;
+ typedef senf::detail::packet::difference_type difference_type;
+ typedef senf::detail::packet::byte byte;
+ typedef byte value_type;
+ typedef byte & reference;
+ typedef byte const & const_reference;
+ typedef byte * pointer;
+ typedef byte const * const_pointer;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // no public constructors
+ // no conversion constructors
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///\name Sequence interface to raw data
+ ///@{
+
+ iterator begin() const;
+ iterator end() const;
+ size_type size() const;
+ bool empty() const;
+ byte operator[](size_type n) const;
+ byte & operator[](size_type n);
+
+ // Modifying the raw packet data
+
+ // IMPORTANT NOTE: It is not possible to insert data AFTER an empty packet
+ // since for an empty packet begin() == end(). However, I hope this problem is
+ // only academic since what should an empty packet be good for ?
+ void insert(iterator pos, byte v);
+ void insert(iterator pos, size_type n, byte v);
+ template <class InputIterator>
+ void insert(iterator pos, InputIterator f, InputIterator l,
+ typename boost::disable_if< boost::is_convertible<InputIterator,size_type> >::type * = 0);
+
+ void erase(iterator pos);
+ void erase(iterator first, iterator last);
+ void clear();
+
+ void resize(size_type n, byte v=0);
+
+ ///@}
+
+ bool valid();
+
+ protected:
+ PacketData(size_type b, size_type e);
+
+ detail::PacketImpl * impl_;
+
+ detail::PacketImpl & impl() const;
+
+ private:
+ size_type begin_;
+ size_type end_;
+
+ friend class detail::PacketImpl;
+ };
+
+ class PacketParserBase;
+
+ struct TruncatedPacketException : public std::exception
+ { virtual char const * what() const throw() { return "truncated packet"; } };
+
+ class safe_data_iterator
+ : public boost::iterator_facade< safe_data_iterator,
+ PacketData::value_type,
+ boost::random_access_traversal_tag >,
+ public ComparableSafeBool<safe_data_iterator>
+ {
+ public:
+ typedef PacketData::size_type size_type;
+
+ safe_data_iterator();
+ explicit safe_data_iterator(PacketData & data);
+ safe_data_iterator(PacketData & data, PacketData::iterator i);
+ explicit safe_data_iterator(PacketParserBase const & parser);
+
+ safe_data_iterator & operator=(PacketData::iterator i);
+ safe_data_iterator & operator=(PacketParserBase const & parser);
+ operator PacketData::iterator() const;
+
+ bool boolean_test() const;
+
+ PacketData & data() const;
+
+ private:
+ friend class boost::iterator_core_access;
+
+ // iterator_facade interface
+
+ value_type & dereference() const;
+ bool equal(safe_data_iterator const & other) const;
+ difference_type distance_to(safe_data_iterator const & other) const;
+ void increment();
+ void decrement();
+ void advance(difference_type n);
+
+ PacketData::iterator i() const;
+
+ PacketData * data_;
+ size_type i_;
+ };
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#endif
+#if !defined(HH_PacketData_DeclOnly) &&!defined(HH_PacketData_def)
+#define HH_PacketData_def
+#include "PacketData.cci"
+//#include "PacketData.ct"
+#include "PacketData.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketData.test unit tests */
+
+//#include "PacketData.test.hh"
+//#include "PacketData.test.ih"
+
+// Custom includes
+#include "PacketData.hh"
+#include "PacketType.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase {};
+}
+
+BOOST_AUTO_UNIT_TEST(packetData)
+{
+ // We cannot simply allocate a packetData instance .. we must go through PacketInterpreterBase
+ // and PacketImpl.
+
+ senf::PacketInterpreterBase::ptr pi (senf::PacketInterpreter<VoidPacket>::create());
+
+ senf::PacketData & d (pi->data());\
+
+ BOOST_CHECK( d.begin() == d.end() );
+ BOOST_CHECK_EQUAL( d.size(), 0u );
+ BOOST_CHECK( d.empty() );
+
+ d.insert(d.begin(), 0xabu);
+ BOOST_CHECK_EQUAL( d.size(), 1u );
+ BOOST_CHECK_EQUAL( d[0], 0xabu );
+ BOOST_CHECK( !d.empty() );
+
+ d.insert(d.begin(), 10, 0xcdu );
+ BOOST_CHECK_EQUAL( d.size(), 11u );
+ BOOST_CHECK_EQUAL( d[0], 0xcdu );
+ BOOST_CHECK_EQUAL( d[9], 0xcdu );
+ BOOST_CHECK_EQUAL( d[10], 0xabu );
+
+ senf::PacketData::byte data[] =
+ { 0xf0u, 0xf1u, 0xf2u, 0xf3u, 0xf4u, 0xf5u, 0xf6u, 0xf7u };
+ d.insert(d.begin()+5, data, data+sizeof(data)/sizeof(data[0]));
+ BOOST_CHECK_EQUAL( d.size(), 19u );
+ BOOST_CHECK_EQUAL( d[4], 0xcdu );
+ BOOST_CHECK_EQUAL( d[5], 0xf0u );
+ BOOST_CHECK_EQUAL( d[12], 0xf7u );
+
+ d.erase(d.begin());
+ BOOST_CHECK_EQUAL( d.size(), 18u );
+ BOOST_CHECK_EQUAL( d[4], 0xf0u );
+
+ d.erase(d.begin(), d.begin()+11);
+ BOOST_CHECK_EQUAL( d.size(), 7u );
+ BOOST_CHECK_EQUAL( d[0], 0xf7u );
+
+ d.resize(16u, 0xefu);
+ BOOST_CHECK_EQUAL( d.size(), 16u );
+ BOOST_CHECK_EQUAL( d[15], 0xefu );
+ BOOST_CHECK_EQUAL( d[6], 0xabu );
+
+ d.resize(8u, 0xbcu);
+ BOOST_CHECK_EQUAL( d.size(), 8u );
+ BOOST_CHECK_EQUAL( d[7], 0xefu );
+
+ d.clear();
+ BOOST_CHECK_EQUAL( d.size(), 0u );
+ BOOST_CHECK( d.empty() );
+}
+
+BOOST_AUTO_UNIT_TEST(safePacketIterator)
+{
+ // We cannot simply allocate a packetData instance .. we must go through PacketInterpreterBase
+ // and PacketImpl.
+
+ senf::PacketInterpreterBase::ptr pi (senf::PacketInterpreter<VoidPacket>::create());
+
+ senf::PacketData & d (pi->data());
+
+ senf::safe_data_iterator i;
+
+ BOOST_CHECK( ! i );
+ i = senf::safe_data_iterator(d);
+ BOOST_CHECK( i );
+ i = d.begin();
+ BOOST_CHECK( i == senf::safe_data_iterator(d,d.begin()) );
+ BOOST_CHECK( senf::PacketData::iterator(i) == d.begin() );
+
+ senf::PacketData::byte data[] =
+ { 0xf0u, 0xf1u, 0xf2u, 0xf3u, 0xf4u, 0xf5u, 0xf6u, 0xf7u };
+ d.resize(sizeof(data)/sizeof(data[0]));
+ BOOST_CHECK( senf::PacketData::iterator(i) == d.begin() );
+ std::copy(data,data+sizeof(data)/sizeof(data[0]),i);
+
+ BOOST_CHECK_EQUAL( d.size(), sizeof(data)/sizeof(data[0]) );
+ BOOST_CHECK_EQUAL( *(i+sizeof(data)/sizeof(data[0])-1), 0xf7u );
+ BOOST_CHECK_EQUAL( std::distance(i,senf::safe_data_iterator(d,d.end())),
+ senf::PacketData::difference_type(d.size()) );
+ *(++i) = 0x01u;
+ BOOST_CHECK_EQUAL( d[1], 0x01u );
+ *(--i) = 0x02u;
+ BOOST_CHECK_EQUAL( d[0], 0x02u );
+ BOOST_CHECK( &d == &i.data() );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketImpl non-inline non-template implementation */
+
+#include "PacketImpl.hh"
+//#include "PacketImpl.ih"
+
+// Custom includes
+#include <iterator>
+#include "PacketInterpreter.hh"
+
+//#include "PacketImpl.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::PacketImpl
+
+// interpreter chain
+
+prefix_ void senf::detail::PacketImpl::appendInterpreter(PacketInterpreterBase * p)
+{
+ interpreters_.push_back(*p);
+ p->assignImpl(this);
+}
+
+prefix_ void senf::detail::PacketImpl::prependInterpreter(PacketInterpreterBase * p)
+{
+ interpreters_.push_front(*p);
+ p->assignImpl(this);
+}
+
+// Data container
+
+prefix_ void senf::detail::PacketImpl::clear(PacketData * self)
+{
+ PacketInterpreterBase * n (next(static_cast<PacketInterpreterBase*>(self)));
+ if (n)
+ truncateInterpreters(n);
+ iterator first (boost::next(begin(),self->begin_));
+ data_.erase(first, boost::next(begin(),self->end_));
+ updateIterators(self,first,-self->size());
+}
+
+// private members
+
+prefix_ void senf::detail::PacketImpl::eraseInterpreters(interpreter_list::iterator b,
+ interpreter_list::iterator e)
+{
+ while (b!=e) {
+ interpreter_list::iterator i (b++);
+ PacketInterpreterBase * p (&(*i));
+ interpreters_.erase(i);
+ p->releaseImpl(); // might call PacketImpl::release and might delete p
+ }
+}
+
+prefix_ void senf::detail::PacketImpl::updateIterators(PacketData * self, iterator pos,
+ difference_type n)
+{
+ // I hate to change the PacketData representation from here, I would have preferred to let
+ // PacketData have authority over this but trying that just get's to convoluted so I choose the
+ // simple solution and made PacketImpl a friend of PacketData.
+
+ interpreter_list::iterator i (interpreters_.begin());
+
+ // There are three types of packets
+ // a) Those which come before 'self' in the interpreter chain
+ // b) 'self'
+ // c) Those that come afterwards
+ // For a), the change must be inside the packet since 'self' must be within those packets
+ // For b), the change must also be within since that's the packet we are changeing
+ // For c), the change must be outside the packet (we don't allow an upper packet to mess with
+ // the the data owned by a packet further down the chain). It can be before or after the
+ // packet.
+
+ // a)
+ for (; &(*i) != static_cast<PacketInterpreterBase*>(self); ++i) i->end_ += n;
+
+ // b)
+ i->end_ += n;
+
+ // c)
+ interpreter_list::iterator const i_end (interpreters_.end());
+ if (++i != i_end)
+ if (std::distance(begin(), pos) < difference_type(i->begin_))
+ // pos is before the packet, it must then be before all futher packets ...
+ for (; i != i_end; ++i) {
+ i->begin_ += n;
+ i->end_ += n;
+ }
+ // else pos is after the packet and we don't need to change anything ...
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "PacketImpl.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketImpl inline non-template implementation */
+
+// Custom includes
+#include "PacketInterpreter.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+// Memory management:
+//
+// * The PacketImpl destructor will *explicitly* clean-up the interpreters_ list by removing
+// each element from the list and deleting it if it's (intrusive) refcount is 0
+// * The PacketInterpreters use safe hooks -> they know wether they are part of a list or not
+// * PacketHandle has an intrusive_ptr to PacketInterpreterBase. The intrusive_ptr_add_ref
+// will refcount both the PacketImpl as well as the PacketInterpreterBase
+// * intrusive_ptr_remove will only delete the object if it's not in a container
+// * removing an object from the list will decrement the PacketImpl refcount accordingly
+// * inserting an object into the list will incroment the PacketImpl refcount accordingly
+// * each PacketInterpreterBase instance holds a *raw* pointer to the PacketImpl
+//
+// The following operations change refcounts:
+//
+// * intrusive_ptr_add_ref(PacketInterpreterBase *);
+// * intrusive_ptr_remove(PacketInterpreterBase *);
+// * PacketImpl::appendInterpreter();
+// * PacketImpl::prependInterpreter();
+// * PacketImpl::truncateInterpreters();
+//
+// The last three also modify the impl_ member accordingly by calling
+// PacketInterpreterBase::assign/release
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::PacketImpl
+
+prefix_ senf::detail::PacketImpl::PacketImpl()
+ : refcount_(0)
+{}
+
+prefix_ senf::detail::PacketImpl::PacketImpl(size_type size, byte initValue)
+ : refcount_(0), data_(size,initValue)
+{}
+
+prefix_ senf::detail::PacketImpl::~PacketImpl()
+{
+ // We increment refcount_ to ensure, release() won't call delete again
+ ++refcount_;
+ eraseInterpreters(interpreters_.begin(), interpreters_.end());
+}
+
+// rerference/memory management
+
+prefix_ void senf::detail::PacketImpl::add_ref(refcount_t n)
+{
+ refcount_ += n;
+}
+
+prefix_ void senf::detail::PacketImpl::release(refcount_t n)
+{
+ BOOST_ASSERT(refcount_ >= n);
+ // uah ... we need to be extremely careful here. If refcount_ is n, we want to commit suicide,
+ // however the destructor will remove all PacketInterpreters from the list and will thereby
+ // decrement refcount -> only decrenebt refcount_ when *not* caling delete
+ if (refcount_ == n)
+ delete this;
+ else
+ refcount_ -= n;
+}
+
+prefix_ senf::detail::PacketImpl::refcount_t senf::detail::PacketImpl::refcount()
+ const
+{
+ return refcount_;
+}
+
+// Interpreter chain
+
+prefix_ senf::PacketInterpreterBase * senf::detail::PacketImpl::first()
+{
+ return interpreters_.empty() ? 0 : & interpreters_.front();
+}
+
+prefix_ senf::PacketInterpreterBase * senf::detail::PacketImpl::last()
+{
+ return interpreters_.empty() ? 0 : & interpreters_.back();
+}
+
+prefix_ senf::PacketInterpreterBase * senf::detail::PacketImpl::next(PacketInterpreterBase * p)
+{
+ interpreter_list::iterator i (interpreter_list::current(*p));
+ return (++i == interpreters_.end()) ? 0 : &*i;
+}
+
+prefix_ senf::PacketInterpreterBase * senf::detail::PacketImpl::prev(PacketInterpreterBase * p)
+{
+ interpreter_list::iterator i (interpreter_list::current(*p));
+ return (i == interpreters_.begin()) ? 0 : &*(--i);
+}
+
+prefix_ void senf::detail::PacketImpl::truncateInterpreters(PacketInterpreterBase * p)
+{
+ Guard guard (this);
+ eraseInterpreters(interpreter_list::current(*p),interpreters_.end());
+}
+
+prefix_ void senf::detail::PacketImpl::truncateInterpretersBackwards(PacketInterpreterBase * p)
+{
+ Guard guard (this);
+ eraseInterpreters(interpreters_.begin(),boost::next(interpreter_list::current(*p)));
+}
+
+// Data container
+
+prefix_ senf::detail::PacketImpl::iterator senf::detail::PacketImpl::begin()
+{
+ return data_.begin();
+}
+
+prefix_ senf::detail::PacketImpl::iterator senf::detail::PacketImpl::end()
+{
+ return data_.end();
+}
+
+prefix_ senf::detail::PacketImpl::size_type senf::detail::PacketImpl::size()
+{
+ return data_.size();
+}
+
+prefix_ void senf::detail::PacketImpl::insert(PacketData * self, iterator pos, byte v)
+{
+ data_.insert(pos,v);
+ updateIterators(self,pos,1);
+}
+
+prefix_ void senf::detail::PacketImpl::insert(PacketData * self, iterator pos, size_type n,
+ byte v)
+{
+ data_.insert(pos,n,v);
+ updateIterators(self,pos,n);
+}
+
+prefix_ void senf::detail::PacketImpl::erase(PacketData * self, iterator pos)
+{
+ data_.erase(pos);
+ updateIterators(self,pos,-1);
+}
+
+prefix_ void senf::detail::PacketImpl::erase(PacketData * self, iterator first, iterator last)
+{
+ data_.erase(first,last);
+ updateIterators(self,first,-std::distance(first,last));
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::PacketImpl::Guard
+
+prefix_ senf::detail::PacketImpl::Guard::Guard(PacketImpl * impl)
+ : p (impl)
+{
+ p->add_ref();
+}
+
+prefix_ senf::detail::PacketImpl::Guard::~Guard()
+{
+ p->release();
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of inline template functions
+/** \file
+ \brief PacketImpl inline template implementation */
-//#include "UDPPacket.ih"
+//#include "PacketImpl.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <class Arg>
-prefix_ senf::UDPPacket::UDPPacket(Arg const & arg)
- : Packet(arg)
-{}
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::PacketImpl
+// Data container
+template <class ForwardIterator>
+prefix_ void senf::detail::PacketImpl::insert(PacketData * self, iterator pos, ForwardIterator f,
+ ForwardIterator l)
+{
+ data_.insert(pos,f,l);
+ updateIterators(self,pos,std::distance(f,l));
+}
+
+template <class InputIterator>
+prefix_ senf::detail::PacketImpl::PacketImpl(InputIterator first, InputIterator last)
+ : refcount_(0), data_(first,last)
+{}
///////////////////////////////cti.e///////////////////////////////////////
#undef prefix_
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketImpl public header */
+
+#ifndef HH_PacketImpl_
+#define HH_PacketImpl_ 1
+
+// Custom includes
+#include <memory>
+#include <boost/utility.hpp>
+#include "Utils/pool_alloc_mixin.hh"
+#include "PacketTypes.hh"
+
+//#include "PacketImpl.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace detail {
+
+ class PacketImpl
+ : boost::noncopyable,
+ public pool_alloc_mixin<PacketImpl>
+ {
+ public:
+ typedef senf::detail::packet::byte byte;
+ typedef senf::detail::packet::raw_container raw_container;
+ typedef senf::detail::packet::size_type size_type;
+ typedef senf::detail::packet::difference_type difference_type;
+ typedef senf::detail::packet::interpreter_list interpreter_list;
+ typedef senf::detail::packet::iterator iterator;
+ typedef senf::detail::packet::const_iterator const_iterator;
+ typedef senf::detail::packet::refcount_t refcount_t;
+
+ // structors
+
+ PacketImpl();
+ PacketImpl(size_type size, byte initValue);
+ template <class InputIterator>
+ PacketImpl(InputIterator b, InputIterator e);
+ ~PacketImpl();
+
+ // rerference/memory management
+
+ void add_ref(refcount_t n=1);
+ void release(refcount_t n=1);
+ refcount_t refcount() const;
+
+ // Interpreter chain
+
+ PacketInterpreterBase * first();
+ PacketInterpreterBase * last();
+
+ PacketInterpreterBase * next(PacketInterpreterBase * p);
+ PacketInterpreterBase * prev(PacketInterpreterBase * p);
+
+ void appendInterpreter (PacketInterpreterBase * p);
+ void prependInterpreter (PacketInterpreterBase * p);
+ void truncateInterpreters (PacketInterpreterBase * p);
+ void truncateInterpretersBackwards (PacketInterpreterBase * p);
+
+ // Data container
+
+ iterator begin();
+ iterator end();
+ size_type size();
+
+ void insert(PacketData * self, iterator pos, byte v);
+ void insert(PacketData * self, iterator pos, size_type n, byte v);
+ template <class ForwardIterator>
+ void insert(PacketData * self, iterator pos, ForwardIterator f, ForwardIterator l);
+
+ void erase(PacketData * self, iterator pos);
+ void erase(PacketData * self, iterator first, iterator last);
+ void clear(PacketData * self);
+
+ // The Guard will keep the PacketImpl instance alive during a members execution time
+ // It the refcount should drop to 0, PacketImpl will be deleted after the member
+ // has completed executing.
+ struct Guard {
+ Guard(PacketImpl * impl);
+ ~Guard();
+ PacketImpl * p;
+ };
+
+ private:
+ refcount_t refcount_;
+ raw_container data_;
+ interpreter_list interpreters_;
+
+ void eraseInterpreters(interpreter_list::iterator b, interpreter_list::iterator e);
+ void updateIterators(PacketData * self, iterator pos, difference_type n);
+
+ };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "PacketImpl.cci"
+//#include "PacketImpl.ct"
+#include "PacketImpl.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketImpl.test unit tests */
+
+//#include "PacketImpl.test.hh"
+//#include "PacketImpl.test.ih"
+
+// Custom includes
+#include "PacketImpl.hh"
+#include "PacketInterpreter.hh"
+#include "PacketType.hh"
+#include "main.test.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase {};
+}
+
+// PacketImpl cannot be tested without relying on PacketInterpreterBase. However these unit-tests
+// only validate PacketInterpreterBase as far as to ensure that a failure of one test is not due to
+// an error in PacketInterpreterbase
+
+BOOST_AUTO_UNIT_TEST(packetImpl_mem)
+{
+ senf::detail::PacketImpl * p (new senf::detail::PacketImpl());
+ BOOST_CHECK_EQUAL(p->refcount(), 0);
+ p->add_ref();
+ BOOST_CHECK_EQUAL(p->refcount(), 1);
+ BOOST_CHECK_EQUAL(
+ senf::pool_alloc_mixin<senf::detail::PacketImpl>::allocCounter(), 1u);
+ // From now on, the object should stay alive since I manually incremented the
+ // refcount ..
+
+
+ p->add_ref(2);
+ BOOST_CHECK_EQUAL(p->refcount(), 3);
+ p->release(2);
+ BOOST_CHECK_EQUAL(p->refcount(), 1);
+
+ {
+ senf::PacketInterpreterBase::ptr pi (
+ senf::detail::packet::test::TestDriver::create<VoidPacket>(
+ p,p->begin(),p->end(), senf::PacketInterpreterBase::Append));
+ // Hmm ... this check works as long as sizeof(PacketInterpreterBase> !=
+ // sizeof(PacketImpl) ... !!
+ BOOST_CHECK_EQUAL(
+ senf::pool_alloc_mixin< senf::PacketInterpreter<VoidPacket> >::allocCounter(), 1u);
+ senf::PacketInterpreterBase::ptr pi2 (pi);
+ BOOST_CHECK_EQUAL(p->refcount(), 3);
+ }
+ BOOST_CHECK_EQUAL(p->refcount(),1);
+
+ {
+ senf::PacketInterpreterBase::ptr pi (p->first());
+ BOOST_CHECK_EQUAL(p->refcount(),2);
+ p->truncateInterpreters(pi.get());
+ BOOST_CHECK_EQUAL(p->refcount(),1);
+ }
+ BOOST_CHECK_EQUAL(
+ senf::pool_alloc_mixin<senf::PacketInterpreterBase>::allocCounter(), 0u);
+ BOOST_CHECK_EQUAL(p->refcount(),1);
+
+
+ // The refcount must be one here (from incrementing the refcount above)
+ // Therefore we can safely delete the object.
+ BOOST_CHECK_EQUAL(p->refcount(), 1);
+ p->release();
+ BOOST_CHECK_EQUAL(
+ senf::pool_alloc_mixin<senf::detail::PacketImpl>::allocCounter(), 0u);
+}
+
+BOOST_AUTO_UNIT_TEST(packetImpl_data)
+{
+ senf::PacketInterpreterBase::ptr pi (senf::PacketInterpreter<VoidPacket>::create());
+ senf::detail::PacketImpl * p (senf::detail::packet::test::TestDriver::impl(pi));
+
+ senf::detail::PacketImpl::byte data[] =
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+
+ p->insert(&pi->data(),p->begin(),data, data+sizeof(data));
+ BOOST_CHECK_EQUAL(p->size(), 8u);
+ BOOST_CHECK_EQUAL(p->begin()[0], 0x00u);
+ BOOST_CHECK_EQUAL(p->begin()[7], 0x07u);
+ BOOST_CHECK_EQUAL(pi->data().size(), p->size());
+
+ p->insert(&pi->data(),p->begin()+2,0xf0u);
+ BOOST_CHECK_EQUAL(p->size(),9u);
+ BOOST_CHECK_EQUAL(p->begin()[8], 0x07u);
+ BOOST_CHECK_EQUAL(p->begin()[2], 0xf0u);
+ BOOST_CHECK_EQUAL(pi->data().size(), p->size());
+
+ p->insert(&pi->data(),p->begin()+9,8,0xffu);
+ BOOST_CHECK_EQUAL(p->size(),17u);
+ BOOST_CHECK_EQUAL(p->begin()[16], 0xffu);
+ BOOST_CHECK_EQUAL(p->begin()[8], 0x07u);
+ BOOST_CHECK_EQUAL(pi->data().size(), p->size());
+
+ p->erase(&pi->data(),p->begin());
+ BOOST_CHECK_EQUAL(p->size(),16u);
+ BOOST_CHECK_EQUAL(p->begin()[0], 0x01u);
+ BOOST_CHECK_EQUAL(pi->data().size(), p->size());
+
+ p->erase(&pi->data(),p->begin()+2, p->begin()+7);
+ BOOST_CHECK_EQUAL(p->size(),11u);
+ BOOST_CHECK_EQUAL(p->begin()[2], 0x07u);
+ BOOST_CHECK_EQUAL(p->begin()[3], 0xffu);
+ BOOST_CHECK_EQUAL(pi->data().size(), p->size());
+
+ BOOST_REQUIRE_EQUAL(pi->data().size(), p->size());
+ BOOST_REQUIRE(pi->data().begin() == p->begin());
+
+ p->clear(&pi->data());
+ BOOST_CHECK_EQUAL(p->size(), 0u);
+ BOOST_CHECK_EQUAL(pi->data().size(), 0u);
+ BOOST_CHECK(pi->data().begin() == p->begin());
+}
+
+BOOST_AUTO_UNIT_TEST(packetImpl_interpreters)
+{
+ senf::detail::PacketImpl * p (new senf::detail::PacketImpl());
+ p->add_ref();
+
+ {
+ senf::PacketInterpreterBase::ptr pi2 (
+ senf::detail::packet::test::TestDriver::create<VoidPacket>(
+ p,p->begin(),p->end(),senf::PacketInterpreterBase::Append));
+ senf::PacketInterpreterBase::ptr pi3 (
+ senf::detail::packet::test::TestDriver::create<VoidPacket>(
+ p,p->end(),p->end(),senf::PacketInterpreterBase::Append));
+ senf::PacketInterpreterBase::ptr pi1 (
+ senf::detail::packet::test::TestDriver::create<VoidPacket>(
+ p,p->begin(),p->end(),senf::PacketInterpreterBase::Prepend));
+
+ BOOST_CHECK_EQUAL(p->first(), pi1.get());
+ BOOST_CHECK_EQUAL(p->next(p->first()), pi2.get());
+ BOOST_CHECK_EQUAL(p->next(p->next(p->first())), pi3.get());
+ BOOST_CHECK( !p->next(p->next(p->next(p->first()))) );
+
+ BOOST_CHECK_EQUAL(p->last(), pi3.get());
+ BOOST_CHECK_EQUAL(p->prev(p->last()), pi2.get());
+ BOOST_CHECK_EQUAL(p->prev(p->prev(p->last())), pi1.get());
+ BOOST_CHECK( !p->prev(p->prev(p->prev(p->last()))) );
+
+ p->insert(&pi2->data(),p->begin(),10,0x00u);
+ BOOST_CHECK_EQUAL(pi1->data().size(), 10u);
+ BOOST_CHECK_EQUAL(pi2->data().size(), 10u);
+ BOOST_CHECK_EQUAL(pi3->data().size(), 0u);
+ BOOST_CHECK( pi1->data().begin() == p->begin() );
+ BOOST_CHECK( pi2->data().begin() == p->begin() );
+ BOOST_CHECK( pi3->data().begin() == p->end() );
+
+ p->insert(&pi3->data(),p->end(), 0x00u);
+ BOOST_CHECK_EQUAL(pi1->data().size(), 11u);
+ BOOST_CHECK_EQUAL(pi2->data().size(), 11u);
+ BOOST_CHECK_EQUAL(pi3->data().size(), 1u);
+
+ p->insert(&pi1->data(),p->end(), 2, 0x00u);
+ BOOST_CHECK_EQUAL(pi1->data().size(), 13u);
+ BOOST_CHECK_EQUAL(pi2->data().size(), 11u);
+ BOOST_CHECK_EQUAL(pi3->data().size(), 1u);
+ BOOST_CHECK( pi1->data().end() == p->begin()+13u );
+ BOOST_CHECK( pi2->data().end() == p->begin()+11u );
+ BOOST_CHECK( pi3->data().end() == p->begin()+11u );
+
+ p->clear(&pi2->data());
+ BOOST_CHECK_EQUAL(pi1->data().size(), 2u);
+ BOOST_CHECK( ! p->next(p->next(p->first())) );
+ }
+
+ BOOST_CHECK_EQUAL(p->refcount(), 1);
+ p->release();
+ BOOST_CHECK_EQUAL(
+ senf::pool_alloc_mixin<senf::detail::PacketImpl>::allocCounter(), 0u);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketInterpreter non-inline non-template implementation */
+
+#include "PacketInterpreter.hh"
+//#include "PacketInterpreter.ih"
+
+// Custom includes
+
+//#include "PacketInterpreter.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreterBase
+
+// structors and default members
+
+prefix_ senf::PacketInterpreterBase::~PacketInterpreterBase()
+{}
+
+prefix_ senf::PacketInterpreterBase::ptr senf::PacketInterpreterBase::clone()
+{
+ detail::PacketImpl::Guard p (new detail::PacketImpl(begin(),end()));
+ ptr pi (appendClone(p.p,begin(),p.p->begin()));
+ for (ptr i (next()); i; i = i->next())
+ i->appendClone(p.p,begin(),p.p->begin());
+ return pi;
+}
+
+// Interpreter chain access
+
+prefix_ senf::PacketInterpreterBase::ptr senf::PacketInterpreterBase::append(ptr packet)
+{
+ if (next())
+ impl().truncateInterpreters(next().get());
+
+ optional_range r (nextPacketRange());
+ if (!r)
+ throw InvalidPacketChainException();
+
+ ptr rv (packet->appendClone(&impl(), *r));
+ rv->data().resize(packet->data().size());
+ std::copy(packet->data().begin(), packet->data().end(), rv->data().begin());
+
+ for (ptr p (packet->next()) ; p ; p = p->next())
+ p->appendClone(&impl(), packet->data().begin(), rv->data().begin());
+
+ return rv;
+}
+
+// Access to the abstract interface
+
+prefix_ void senf::PacketInterpreterBase::dump(std::ostream & os)
+{
+ v_dump(os);
+ for (ptr i (next()); i; i = i->next())
+ i->v_dump(os);
+}
+
+prefix_ void senf::PacketInterpreterBase::finalize()
+{
+ for (ptr i (last()) ; i.get() != this ; i = i->prev())
+ i->v_finalize();
+ v_finalize();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreterBase::Factory
+
+prefix_ senf::PacketInterpreterBase::Factory::~Factory()
+{}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "PacketInterpreter.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketInterpreter inline non-template implementation */
+
+// Custom includes
+#include <boost/utility.hpp>
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreterBase
+
+// Structors and default members
+
+prefix_ senf::PacketInterpreterBase::factory_t senf::PacketInterpreterBase::no_factory()
+{
+ return 0;
+}
+
+// Interpreter chain access
+
+prefix_ senf::PacketInterpreterBase::ptr senf::PacketInterpreterBase::next()
+{
+ return ptr(impl().next(this));
+}
+
+prefix_ senf::PacketInterpreterBase::ptr senf::PacketInterpreterBase::prev()
+{
+ return ptr(impl().prev(this));
+}
+
+prefix_ senf::PacketInterpreterBase::ptr senf::PacketInterpreterBase::first()
+{
+ return ptr(impl().first());
+}
+
+prefix_ senf::PacketInterpreterBase::ptr senf::PacketInterpreterBase::last()
+{
+ return ptr(impl().last());
+}
+
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreterBase::parseNextAs(factory_t factory)
+{
+ return factory->parseNext(ptr(this));
+}
+
+// Data access
+
+prefix_ senf::PacketData & senf::PacketInterpreterBase::data()
+{
+ return (*this);
+}
+
+// Access to the abstract interface
+
+prefix_ senf::PacketInterpreterBase::optional_range
+senf::PacketInterpreterBase::nextPacketRange()
+{
+ return v_nextPacketRange();
+}
+
+prefix_ senf::TypeIdValue senf::PacketInterpreterBase::typeId()
+{
+ return v_type();
+}
+
+prefix_ senf::PacketInterpreterBase::factory_t senf::PacketInterpreterBase::factory()
+{
+ return v_factory();
+}
+
+prefix_ senf::PacketInterpreterBase::factory_t senf::PacketInterpreterBase::nextPacketType()
+{
+ return v_nextPacketType();
+}
+
+////////////////////////////////////////
+// protected members
+
+// protected structors
+
+prefix_ senf::PacketInterpreterBase::PacketInterpreterBase(detail::PacketImpl * impl,
+ iterator b, iterator e, Append_t)
+ : PacketData(std::distance(impl->begin(),b),
+ std::distance(impl->begin(),e))
+{
+ impl->appendInterpreter(this);
+}
+
+prefix_ senf::PacketInterpreterBase::PacketInterpreterBase(detail::PacketImpl * impl,
+ iterator b, iterator e, Prepend_t)
+ : PacketData(std::distance(impl->begin(),b),
+ std::distance(impl->begin(),e))
+{
+ impl->prependInterpreter(this);
+}
+
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreterBase::appendClone(detail::PacketImpl * impl, iterator base,
+ iterator new_base)
+{
+ return v_appendClone(impl,base,new_base);
+}
+
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreterBase::appendClone(detail::PacketImpl * impl, range r)
+{
+ return v_appendClone(impl,r);
+}
+
+////////////////////////////////////////
+// private members
+
+// reference/memory management
+
+prefix_ void senf::PacketInterpreterBase::add_ref()
+{
+ intrusive_refcount_t<PacketInterpreterBase>::add_ref();
+ if (impl_)
+ impl_->add_ref();
+}
+
+prefix_ bool senf::PacketInterpreterBase::release()
+{
+ if (impl_)
+ // This call will set impl_ to 0 if we just removed the last reference ...
+ impl_->release();
+ return intrusive_refcount_t<PacketInterpreterBase>::release() && !impl_;
+}
+
+// containment management. Only to be called by PacketImpl.
+
+prefix_ void senf::PacketInterpreterBase::assignImpl(detail::PacketImpl * impl)
+{
+ BOOST_ASSERT(!impl_);
+ impl_ = impl;
+ impl_->add_ref(refcount());
+}
+
+prefix_ void senf::PacketInterpreterBase::releaseImpl()
+{
+ BOOST_ASSERT(impl_);
+ refcount_t refc (refcount());
+ if (refc) {
+ impl_->release(refc);
+ impl_ = 0;
+ } else {
+ impl_ = 0;
+ delete this;
+ }
+}
+
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketInterpreter non-inline template implementation */
+
+//#include "PacketInterpreter.ih"
+
+// Custom includes
+#include "Packet.hh"
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreterBase
+
+// Interpreter chain access
+
+template <class Type>
+prefix_ typename senf::PacketInterpreter<Type>::ptr
+senf::PacketInterpreterBase::parseNextAs()
+{
+ optional_range r (nextPacketRange());
+ if (!r)
+ throw InvalidPacketChainException();
+
+ if (next())
+ impl().truncateInterpreters(next().get());
+
+ typename PacketInterpreter<Type>::ptr pi
+ (PacketInterpreter<Type>::create(&impl(),r->begin(),r->end(),Append));
+ return pi;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreter<PacketType>
+
+// Create completely new packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create(size_type size)
+{
+ if (size < initSize())
+ throw TruncatedPacketException();
+ ptr pi (create(size,noinit));
+ pi->init();
+ return pi;
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create(size_type size, NoInit_t)
+{
+ detail::PacketImpl::Guard p (new detail::PacketImpl(size,0));
+ ptr pi (create(p.p,p.p->begin(),p.p->end(),Append));
+ return pi;
+}
+
+// Create packet as new packet after a given packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createAfter(PacketInterpreterBase::ptr packet,
+ size_type size)
+{
+ if (size < initSize())
+ throw TruncatedPacketException();
+ ptr pi (createAfter(packet,size,noinit));
+ std::fill(pi->data().begin(), pi->data().end(),0);
+ pi->init();
+ return pi;
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createAfter(PacketInterpreterBase::ptr packet,
+ size_type size, NoInit_t)
+{
+ optional_range r (packet->nextPacketRange());
+ if (!r)
+ throw InvalidPacketChainException();
+
+ if (packet->next())
+ packet->impl().truncateInterpreters(packet->next().get());
+
+ ptr pi (create(&packet->impl(),r->begin(),r->end(),Append));
+ pi->data().resize(size);
+ return pi;
+}
+
+template <class PacketType>
+template <class ForwardReadableRange>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createAfter(PacketInterpreterBase::ptr packet,
+ ForwardReadableRange const & range)
+{
+ optional_range r (packet->nextPacketRange());
+ if (!r)
+ throw InvalidPacketChainException();
+
+ if (packet->next())
+ packet->impl().truncateInterpreters(packet->next().get());
+
+ ptr pi (create(&packet->impl(),r->begin(),r->end(),Append));
+ pi->data().resize(boost::size(range));
+ std::copy(boost::begin(range), boost::end(range), pi->data().begin());
+ return pi;
+}
+
+// Create packet as new packet (header) before a given packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createBefore(PacketInterpreterBase::ptr packet)
+{
+ ptr pi (createBefore(packet, noinit));
+ pi->data().insert(pi->data().begin(),initHeadSize(),byte(0x00u));
+ pi->data().insert(pi->data().end(),initSize()-initHeadSize(),byte(0x00u));
+ pi->init();
+ return pi;
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createBefore(PacketInterpreterBase::ptr packet, NoInit_t)
+{
+ if (packet->prev())
+ packet->impl().truncateInterpretersBackwards(packet->prev().get());
+
+ return create(&packet->impl(),packet->data().begin(),packet->data().end(),Prepend);
+}
+
+////////////////////////////////////////
+// private members
+
+// virtual interface
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::optional_range
+senf::PacketInterpreter<PacketType>::v_nextPacketRange()
+{
+ return type::nextPacketRange(ConcretePacket<PacketType>(ptr(this)));
+}
+
+template <class PacketType>
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::v_appendClone(detail::PacketImpl * impl, iterator base,
+ iterator new_base)
+{
+ return create(impl,
+ boost::next(new_base,std::distance(base,begin())),
+ boost::next(new_base,std::distance(base,end())),
+ Append);
+}
+
+template <class PacketType>
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::v_appendClone(detail::PacketImpl * impl, range r)
+{
+ return create(impl, r.begin(), r.end(), Append);
+}
+
+template <class PacketType>
+prefix_ void senf::PacketInterpreter<PacketType>::v_finalize()
+{
+ type::finalize(ConcretePacket<PacketType>(ptr(this)));
+}
+
+template <class PacketType>
+prefix_ void senf::PacketInterpreter<PacketType>::v_dump(std::ostream & os)
+{
+ type::dump(ConcretePacket<PacketType>(ptr(this)),os);
+}
+
+template <class PacketType>
+prefix_ senf::TypeIdValue senf::PacketInterpreter<PacketType>::v_type()
+{
+ return typeIdValue<PacketType>();
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::factory_t
+senf::PacketInterpreter<PacketType>::v_factory()
+{
+ return factory();
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::factory_t
+senf::PacketInterpreter<PacketType>::v_nextPacketType()
+{
+ return type::nextPacketType(ConcretePacket<PacketType>(ptr(this)));
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreterBase::Factory
+
+template <class ForwardReadableRange>
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreterBase::Factory::create(ForwardReadableRange const & range)
+ const
+{
+ ptr pi (create(boost::size(range),noinit));
+ std::copy(boost::begin(range), boost::end(range), pi->data().begin());
+ return pi;
+}
+
+template <class ForwardReadableRange>
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreterBase::Factory::createAfter(PacketInterpreterBase::ptr packet,
+ ForwardReadableRange const & range)
+ const
+{
+ ptr pi (createAfter(packet,boost::size(range),noinit));
+ std::copy(boost::begin(range), boost::end(range), pi->data().begin());
+ return pi;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreter<PacketType>::FactoryImpl
+
+// Create completely new packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::create()
+ const
+{
+ return senf::PacketInterpreter<PacketType>::create();
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::create(NoInit_t)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::create(noinit);
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::create(size_type size)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::create(size);
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::create(size_type size, NoInit_t)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::create(size, noinit);
+}
+
+// Create packet as new packet after a given packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::createAfter(PacketInterpreterBase::ptr packet)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::createAfter(packet);
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::createAfter(PacketInterpreterBase::ptr packet,
+ NoInit_t)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::createAfter(packet,noinit);
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::createAfter(PacketInterpreterBase::ptr packet,
+ size_type size)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::createAfter(packet,size);
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::createAfter(PacketInterpreterBase::ptr packet,
+ size_type size, NoInit_t)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::createAfter(packet,size,noinit);
+}
+
+// Create packet as new packet (header) before a given packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::
+createBefore(PacketInterpreterBase::ptr packet)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::createBefore(packet);
+}
+
+template <class PacketType>
+prefix_ senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::
+createBefore(PacketInterpreterBase::ptr packet, NoInit_t)
+ const
+{
+ return senf::PacketInterpreter<PacketType>::createBefore(packet,noinit);
+}
+
+// Parse next packet in chain
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreterBase::ptr
+senf::PacketInterpreter<PacketType>::FactoryImpl::parseNext(PacketInterpreterBase::ptr packet)
+ const
+{
+ optional_range r (packet->nextPacketRange());
+ if (!r)
+ throw InvalidPacketChainException();
+
+ if (packet->next())
+ packet->impl().truncateInterpreters(packet->next().get());
+
+ return senf::PacketInterpreter<PacketType>::create(&packet->impl(),r->begin(),r->end(),Append);
+}
+
+template <class PacketType>
+const typename senf::PacketInterpreter<PacketType>::FactoryImpl
+ senf::PacketInterpreter<PacketType>::factory_;
+
+///////////////////////////////ct.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketInterpreter inline template implementation */
+
+//#include "PacketInterpreter.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreterBase
+
+// Interpreter chain access
+
+template <class Type>
+prefix_ bool senf::PacketInterpreterBase::is()
+{
+ return dynamic_cast< PacketInterpreter<Type>* >(this);
+}
+
+template <class Type>
+prefix_ typename senf::PacketInterpreter<Type>::ptr senf::PacketInterpreterBase::as()
+{
+ return typename PacketInterpreter<Type>::ptr(
+ static_cast< PacketInterpreter<Type>* >(this));
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketInterpreter<PacketType>
+
+template <class PacketType>
+prefix_ senf::PacketInterpreter<PacketType>::~PacketInterpreter()
+{
+ parser_p()->~parser();
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::factory_t
+senf::PacketInterpreter<PacketType>::factory()
+{
+ return & factory_;
+}
+
+// Create completely new packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create()
+{
+ return create(initSize());
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create(NoInit_t)
+{
+ return create(0,noinit);
+}
+
+template <class PacketType>
+template <class ForwardReadableRange>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create(ForwardReadableRange const & range)
+{
+ detail::PacketImpl::Guard p (new detail::PacketImpl(boost::begin(range),boost::end(range)));
+ ptr pi (create(p.p,p.p->begin(),p.p->end(),Append));
+ return pi;
+}
+
+// Create packet as new packet after a given packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createAfter(PacketInterpreterBase::ptr packet)
+{
+ return createAfter(packet, initSize());
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::createAfter(PacketInterpreterBase::ptr packet, NoInit_t)
+{
+ return createAfter(packet, 0, noinit);
+}
+
+// Create clone of current packet
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::clone()
+{
+ return boost::static_pointer_cast<typename ptr::element_type>(PacketInterpreterBase::clone());
+}
+
+// Packet field access
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::parser
+senf::PacketInterpreter<PacketType>::fields()
+{
+ return parser(&data());
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::parser *
+senf::PacketInterpreter<PacketType>::fields_p()
+{
+ // This is somewhat awkward. We want to allow the user to access the packet's field using the
+ // 'operator->' member of the packet class (the handle). Now, 'operator->' *must* return a
+ // pointer to a non-dynamically allocated object. So where should it point to? We need to return
+ // a pointer to a parser instance, but parser instances are designed to be transient (they are
+ // invalidated whenever a packet's size is changed).
+
+ // What we do is the following: parserStorage_ is an (initialy uninitialized) storage area
+ // within the interpreter with enough space (and correct alignment) to take hold of a parser
+ // instance. In the constructor we use placement new to construct a parser in this area which we
+ // explicit dispose of in the destructor. Now, whenever the fields_p() member is called, we
+ // destroy the parser object and recreate it.
+
+ // This does introduce one additional problem: It is not safe for multiple threads to
+ // concurrently read from the same packet. On the other hand, the packet classes are not
+ // syncronized in any way and are not safe to use from multiple threads anyways (e.g. the lazy
+ // packet chain makes some read-only operations change the packet which is not thread safe).
+
+ parser_p()->~parser();
+ new (parser_p()) parser (data().begin(),&data());
+ return parser_p();
+}
+
+////////////////////////////////////////
+// private members
+
+// Private structors
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create(detail::PacketImpl * impl, iterator b, iterator e,
+ Append_t)
+{
+ return ptr(new PacketInterpreter(impl,b,e,Append));
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::ptr
+senf::PacketInterpreter<PacketType>::create(detail::PacketImpl * impl, iterator b, iterator e,
+ Prepend_t)
+{
+ return ptr(new PacketInterpreter(impl,b,e,Prepend));
+}
+
+template <class PacketType>
+prefix_ senf::PacketInterpreter<PacketType>::PacketInterpreter(detail::PacketImpl * impl,
+ iterator b, iterator e, Append_t)
+ : PacketInterpreterBase(impl,b,e,Append)
+{
+ new (parser_p()) parser (data().begin(),&data());
+}
+
+template <class PacketType>
+prefix_ senf::PacketInterpreter<PacketType>::PacketInterpreter(detail::PacketImpl * impl,
+ iterator b, iterator e, Prepend_t)
+ : PacketInterpreterBase(impl,b,e,Prepend)
+{
+ new (parser_p()) parser (data().begin(),&data());
+}
+
+// PacketType access
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::size_type
+senf::PacketInterpreter<PacketType>::initSize()
+{
+ return type::initSize();
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::size_type
+senf::PacketInterpreter<PacketType>::initHeadSize()
+{
+ size_type sz (type::initHeadSize());
+ return sz == size_type(-1) ? initSize() : sz ;
+}
+
+template <class PacketType>
+prefix_ void senf::PacketInterpreter<PacketType>::init()
+{
+ return type::init(ConcretePacket<PacketType>(ptr(this)));
+}
+
+template <class PacketType>
+prefix_ typename senf::PacketInterpreter<PacketType>::parser *
+senf::PacketInterpreter<PacketType>::parser_p()
+{
+ return reinterpret_cast<parser *>(&parserStorage_);
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketInterpreter public header */
+
+#ifndef HH_PacketInterpreter_
+#define HH_PacketInterpreter_ 1
+
+// Custom includes
+#include <boost/intrusive/ilist.hpp>
+#include <boost/optional.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/aligned_storage.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#include "Utils/intrusive_refcount.hh"
+#include "Utils/pool_alloc_mixin.hh"
+#include "PacketData.hh"
+#include "typeidvalue.hh"
+
+//#include "PacketInterpreter.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ template <class PacketType> class PacketInterpreter;
+
+ /** \brief
+ */
+ class PacketInterpreterBase
+ : protected PacketData,
+ public detail::packet::interpreter_list_base,
+ public intrusive_refcount_t<PacketInterpreterBase>
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef senf::detail::packet::smart_pointer<
+ PacketInterpreterBase>::ptr_t ptr;
+
+ typedef senf::detail::packet::iterator iterator;
+ typedef senf::detail::packet::const_iterator const_iterator;
+ typedef senf::detail::packet::size_type size_type;
+ typedef senf::detail::packet::difference_type difference_type;
+ typedef senf::detail::packet::byte byte;
+
+ typedef boost::iterator_range<iterator> range;
+ typedef boost::optional< boost::iterator_range<iterator> > optional_range;
+ typedef optional_range no_range;
+
+ enum Append_t { Append };
+ enum Prepend_t { Prepend };
+ enum NoInit_t { noinit };
+
+ struct Factory {
+ virtual ~Factory();
+
+ // Create completely new packet
+
+ virtual ptr create() const = 0;
+ virtual ptr create(NoInit_t) const = 0;
+ virtual ptr create(size_type size) const = 0;
+ virtual ptr create(size_type size, NoInit_t) const = 0;
+ template <class ForwardReadableRange>
+ ptr create(ForwardReadableRange const & range) const;
+
+ // Create packet as new packet after a given packet
+
+ virtual ptr createAfter(PacketInterpreterBase::ptr packet) const = 0;
+ virtual ptr createAfter(PacketInterpreterBase::ptr packet, NoInit_t) const = 0;
+ virtual ptr createAfter(PacketInterpreterBase::ptr packet, size_type size) const = 0;
+ virtual ptr createAfter(PacketInterpreterBase::ptr packet, size_type size,
+ NoInit_t) const = 0;
+ template <class ForwardReadableRange>
+ ptr createAfter(PacketInterpreterBase::ptr packet,
+ ForwardReadableRange const & range) const;
+
+ // Create packet as new packet (header) const before a given packet
+
+ virtual ptr createBefore(PacketInterpreterBase::ptr packet) const = 0;
+ virtual ptr createBefore(PacketInterpreterBase::ptr packet, NoInit_t) const = 0;
+
+ // Parse next packet in chain
+
+ virtual ptr parseNext(ptr packet) const = 0;
+ };
+
+ typedef Factory const * factory_t;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // protected constructors
+ // no copy
+ // no conversion constructors
+
+ virtual ~PacketInterpreterBase();
+
+ static factory_t no_factory();
+
+ ptr clone();
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///\name Interpreter chain access
+ ///@{
+
+ ptr next();
+ ptr prev();
+ ptr first();
+ ptr last();
+
+ template <class Type> typename PacketInterpreter<Type>::ptr parseNextAs();
+ ptr parseNextAs(factory_t factory);
+ template <class Type> bool is();
+ template <class Type> typename PacketInterpreter<Type>::ptr as();
+
+ ptr append(ptr packet);
+
+ ///@}
+
+ ///\name Data access
+ ///@{
+
+ using PacketData::valid;
+ PacketData & data();
+
+ ///@}
+
+ ///\name Access to the abstract interface
+ ///@{
+
+ optional_range nextPacketRange();
+ void finalize();
+ void dump(std::ostream & os);
+ TypeIdValue typeId();
+ factory_t factory();
+ factory_t nextPacketType();
+
+ ///@}
+
+ protected:
+ // protected structors
+
+ PacketInterpreterBase(detail::PacketImpl * impl, iterator b, iterator e, Append_t);
+ PacketInterpreterBase(detail::PacketImpl * impl, iterator b, iterator e, Prepend_t);
+
+ ptr appendClone(detail::PacketImpl * impl, iterator base, iterator new_base);
+ ptr appendClone(detail::PacketImpl * impl, range r);
+
+ private:
+ // abstract packet type interface
+
+ virtual optional_range v_nextPacketRange() = 0;
+ virtual ptr v_appendClone(detail::PacketImpl * impl, iterator base, iterator new_base) = 0;
+ virtual ptr v_appendClone(detail::PacketImpl * impl, range r) =0;
+ virtual void v_finalize() = 0;
+ virtual void v_dump(std::ostream & os) = 0;
+ virtual TypeIdValue v_type() = 0;
+ virtual factory_t v_factory() = 0;
+ virtual factory_t v_nextPacketType() = 0;
+
+ // reference/memory management. Only to be called by intrusive_refcount_t.
+
+ void add_ref();
+ bool release();
+
+ // containment management. Only to be called by PacketImpl.
+
+ void assignImpl(detail::PacketImpl *);
+ void releaseImpl();
+
+ friend class detail::PacketImpl;
+ friend class intrusive_refcount_t<PacketInterpreterBase>;
+ template <class PacketType> friend class PacketInterpreter;
+ friend class detail::packet::test::TestDriver;
+ };
+
+ /** \brief Concrete packet interpreter
+
+ \see PacketTypeBase for the \a PacketType interface
+ */
+ template <class PacketType>
+ class PacketInterpreter
+ : public PacketInterpreterBase,
+ public pool_alloc_mixin< PacketInterpreter<PacketType> >
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef typename senf::detail::packet::smart_pointer<
+ PacketInterpreter>::ptr_t ptr;
+ typedef PacketType type;
+ typedef typename type::parser parser;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // private constructors
+ // no copy
+ // no conversion constructors
+
+ ~PacketInterpreter();
+
+ static factory_t factory();
+
+ // Create completely new packet
+
+ static ptr create();
+ static ptr create(NoInit_t);
+ static ptr create(size_type size);
+ static ptr create(size_type size, NoInit_t);
+ template <class ForwardReadableRange>
+ static ptr create(ForwardReadableRange const & range);
+
+ // Create packet as new packet after a given packet
+
+ static ptr createAfter(PacketInterpreterBase::ptr packet);
+ static ptr createAfter(PacketInterpreterBase::ptr packet, NoInit_t);
+ static ptr createAfter(PacketInterpreterBase::ptr packet, size_type size);
+ static ptr createAfter(PacketInterpreterBase::ptr packet, size_type size, NoInit_t);
+ template <class ForwardReadableRange>
+ static ptr createAfter(PacketInterpreterBase::ptr packet,
+ ForwardReadableRange const & range);
+
+ // Create packet as new packet (header) before a given packet
+
+ static ptr createBefore(PacketInterpreterBase::ptr packet);
+ static ptr createBefore(PacketInterpreterBase::ptr packet, NoInit_t);
+
+ // Create a clone of the current packet
+
+ ptr clone();
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Packet field access
+
+ parser fields();
+ parser * fields_p();
+
+ // PacketType access
+
+ static size_type initSize();
+ static size_type initHeadSize();
+
+ protected:
+
+ private:
+ // Private structors
+
+ PacketInterpreter(detail::PacketImpl * impl, iterator b, iterator e, Append_t);
+ PacketInterpreter(detail::PacketImpl * impl, iterator b, iterator e, Prepend_t);
+
+ static ptr create(detail::PacketImpl * impl, iterator b, iterator e, Append_t);
+ static ptr create(detail::PacketImpl * impl, iterator b, iterator e, Prepend_t);
+
+ // PacketType access
+
+ void init();
+
+ // virtual interface
+
+ virtual optional_range v_nextPacketRange();
+ virtual PacketInterpreterBase::ptr v_appendClone(detail::PacketImpl * impl,
+ iterator base, iterator new_base);
+ virtual PacketInterpreterBase::ptr v_appendClone(detail::PacketImpl * impl, range r);
+ virtual void v_finalize();
+ virtual void v_dump(std::ostream & os);
+ virtual TypeIdValue v_type();
+ virtual factory_t v_factory();
+ virtual factory_t v_nextPacketType();
+
+ // factory
+
+ struct FactoryImpl : public Factory {
+ // Create completely new packet
+
+ virtual PacketInterpreterBase::ptr create() const;
+ virtual PacketInterpreterBase::ptr create(NoInit_t) const;
+ virtual PacketInterpreterBase::ptr create(size_type size) const;
+ virtual PacketInterpreterBase::ptr create(size_type size,NoInit_t) const;
+
+ // Create packet as new packet after a given packet
+
+ virtual PacketInterpreterBase::ptr createAfter(PacketInterpreterBase::ptr packet)
+ const;
+ virtual PacketInterpreterBase::ptr createAfter(PacketInterpreterBase::ptr packet,
+ NoInit_t) const;
+ virtual PacketInterpreterBase::ptr createAfter(PacketInterpreterBase::ptr packet,
+ size_type size) const;
+ virtual PacketInterpreterBase::ptr createAfter(PacketInterpreterBase::ptr packet,
+ size_type size, NoInit_t) const;
+
+ // Create packet as new packet (header) before a given packet
+
+ virtual PacketInterpreterBase::ptr createBefore(PacketInterpreterBase::ptr packet)
+ const;
+ virtual PacketInterpreterBase::ptr createBefore(PacketInterpreterBase::ptr packet,
+ NoInit_t)
+ const;
+
+ // Parse next packet in chain
+
+ virtual PacketInterpreterBase::ptr parseNext(PacketInterpreterBase::ptr packet)
+ const;
+ };
+
+ static const FactoryImpl factory_;
+
+ parser * parser_p();
+
+ boost::aligned_storage< sizeof(parser),
+ boost::alignment_of<parser>::value > parserStorage_;
+
+ friend class detail::packet::test::TestDriver;
+ friend class PacketInterpreterBase;
+ friend class FactoryImpl;
+ };
+
+ struct InvalidPacketChainException : public std::exception
+ { virtual char const * what() const throw() { return "invalid packet chain"; } };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "PacketInterpreter.cci"
+#include "PacketInterpreter.ct"
+#include "PacketInterpreter.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketInterpreter.test unit tests */
+
+//#include "PacketInterpreter.test.hh"
+//#include "PacketInterpreter.test.ih"
+
+// Custom includes
+#include "PacketImpl.hh"
+#include "PacketInterpreter.hh"
+#include "PacketType.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase {
+ typedef senf::ConcretePacket<VoidPacket> packet;
+ static optional_range nextPacketRange(packet p)
+ { return range(p.data().begin(), p.data().end()); }
+ };
+}
+
+BOOST_AUTO_UNIT_TEST(packetInterpreterBase)
+{
+ {
+ senf::PacketInterpreter<VoidPacket>::ptr pi2 (senf::PacketInterpreter<VoidPacket>::create());
+ senf::PacketInterpreter<VoidPacket>::ptr pi1 (senf::PacketInterpreter<VoidPacket>::createBefore(pi2));
+
+ pi2->data().insert(pi2->data().begin(),0x02);
+ BOOST_CHECK_EQUAL( pi1->data().size(), 1u );
+ BOOST_CHECK_EQUAL( pi2->data().size(), 1u );
+
+ senf::PacketInterpreter<VoidPacket>::ptr pi3 (pi2->parseNextAs<VoidPacket>());
+ BOOST_REQUIRE( pi3 );
+ BOOST_CHECK( pi2 == pi1->next() );
+ BOOST_CHECK( pi3 == pi2->next() );
+ BOOST_CHECK( ! pi3->next() );
+ BOOST_CHECK( pi2 == pi3->prev() );
+ BOOST_CHECK( pi1 == pi2->prev() );
+ BOOST_CHECK( ! pi1->prev() );
+ BOOST_CHECK( pi2->is<VoidPacket>() );
+ BOOST_CHECK( pi2->as<VoidPacket>() == pi2 );
+ BOOST_CHECK( pi2->parseNextAs(senf::PacketInterpreter<VoidPacket>::factory()) );
+ BOOST_CHECK( pi2->typeId() == pi1->typeId() );
+
+ pi1->data().insert(pi1->data().begin(),2,0x01u);
+ BOOST_CHECK_EQUAL( pi1->data().size(), 3u );
+ BOOST_CHECK_EQUAL( pi2->data().size(), 1u );
+ BOOST_CHECK_EQUAL( pi3->data().size(), 1u );
+
+ senf::PacketInterpreter<VoidPacket>::ptr pi2b (pi2->clone());
+ BOOST_REQUIRE( pi2b->next() );
+ BOOST_CHECK( ! pi2b->next()->next() );
+ BOOST_CHECK( ! pi2b->prev() );
+
+ pi2b->data().insert(pi2b->data().begin(),0x03u);
+ BOOST_CHECK_EQUAL( pi2->data().size(), 1u );
+ BOOST_CHECK_EQUAL( pi2b->data().size(), 2u );
+
+ BOOST_CHECK_EQUAL( pi1->data().size(), pi1->nextPacketRange()->size() );
+ pi1->append(pi2b);
+ BOOST_CHECK_EQUAL( pi1->data().size(), 2u );
+ BOOST_REQUIRE( pi1->next() );
+ BOOST_REQUIRE( pi1->next()->next() );
+ BOOST_CHECK( ! pi1->next()->next()->next() );
+ }
+
+}
+
+namespace {
+ struct OtherPacket
+ : public senf::PacketTypeBase,
+ public senf::PacketTypeMixin<OtherPacket>
+ {
+ using senf::PacketTypeMixin<OtherPacket>::nextPacketRange;
+ typedef senf::ConcretePacket<OtherPacket> packet;
+ static size_type initSize() { return 8u; }
+ static size_type initHeadSize() { return 6u; }
+ static void init(packet p) { p.data()[0] = 0x01u; }
+ };
+}
+
+BOOST_AUTO_UNIT_TEST(packetInterpreter)
+{
+ {
+ BOOST_CHECK_THROW( senf::PacketInterpreter<OtherPacket>::create(4u),
+ senf::TruncatedPacketException );
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(12u));
+
+ BOOST_CHECK_EQUAL( p->data().size(), 12u );
+ BOOST_CHECK_EQUAL( std::distance(p->data().begin(),p->data().end()), 12 );
+ BOOST_CHECK_EQUAL( p->data()[0], 0x01u );
+
+ senf::PacketInterpreter<VoidPacket>::ptr p2
+ (p->parseNextAs<VoidPacket>());
+ BOOST_CHECK_EQUAL( p2->data().size(), 4u );
+ BOOST_CHECK_EQUAL( std::distance(p->data().begin(),p2->data().begin()), 6 );
+
+ senf::PacketInterpreter<OtherPacket>::ptr pc
+ (p->clone());
+ BOOST_CHECK_EQUAL( p->data().size(), 12u );
+ BOOST_CHECK( p->next() );
+ BOOST_CHECK( ! p->next()->next() );
+ }
+
+ {
+ BOOST_CHECK_NO_THROW(
+ senf::PacketInterpreter<OtherPacket>::create(4u,senf::PacketInterpreterBase::noinit));
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(senf::PacketInterpreterBase::noinit));
+ BOOST_CHECK_EQUAL( p->data().size(), 0u );
+ }
+
+ {
+ senf::PacketInterpreter<VoidPacket>::byte data[] = { 0x01, 0x02, 0x03, 0x04 };
+ senf::PacketInterpreter<VoidPacket>::ptr p
+ (senf::PacketInterpreter<VoidPacket>::create(data));
+
+ BOOST_CHECK_EQUAL( p->data().size(), 4u );
+ BOOST_CHECK_EQUAL( std::distance(p->data().begin(),p->data().end()), 4 );
+ BOOST_CHECK( std::equal(p->data().begin(), p->data().end(), data) );
+ }
+
+ {
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(12u));
+ senf::PacketInterpreter<VoidPacket>::ptr p2
+ (senf::PacketInterpreter<VoidPacket>::createAfter(p));
+ BOOST_CHECK_EQUAL( p2->data().size(), 0u );
+ BOOST_CHECK_EQUAL( p->data().size(), 8u );
+ p2->data().insert(p2->data().begin(),0x01u);
+ BOOST_CHECK_EQUAL( p->data()[6], 0x01u );
+ BOOST_CHECK_EQUAL( p->data().size(), 9u );
+ }
+
+ {
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(12u));
+ senf::PacketInterpreter<OtherPacket>::ptr p2
+ (senf::PacketInterpreter<OtherPacket>::createAfter(
+ p,senf::PacketInterpreterBase::noinit));
+ BOOST_CHECK_EQUAL( p2->data().size(), 0u );
+ BOOST_CHECK_EQUAL( p->data().size(), 8u );
+ }
+
+ {
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(12u));
+ senf::PacketInterpreter<OtherPacket>::ptr p2
+ (senf::PacketInterpreter<OtherPacket>::createAfter(p,10u));
+ BOOST_CHECK_EQUAL( p2->data().size(), 10u );
+ BOOST_CHECK_EQUAL( p->data().size(), 18u );
+ BOOST_CHECK_EQUAL( p2->data()[0], 0x01u );
+ BOOST_CHECK_THROW( senf::PacketInterpreter<OtherPacket>::createAfter(p,4u),
+ senf::TruncatedPacketException );
+ BOOST_CHECK_NO_THROW( senf::PacketInterpreter<OtherPacket>::createAfter(
+ p,4u,senf::PacketInterpreterBase::noinit) );
+ }
+
+ {
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(10u));
+ senf::PacketInterpreter<VoidPacket>::byte data[] = { 0x01, 0x02, 0x03, 0x04 };
+ senf::PacketInterpreter<OtherPacket>::ptr p2
+ (senf::PacketInterpreter<OtherPacket>::createAfter(p,data));
+ BOOST_CHECK_EQUAL( p2->data().size(), 4u );
+ BOOST_CHECK_EQUAL( p->data().size(), 12u );
+ BOOST_CHECK_EQUAL( p2->data()[1], 0x02u );
+ BOOST_CHECK_EQUAL( p->data()[8], 0x03u );
+ }
+
+ {
+ senf::PacketInterpreter<OtherPacket>::ptr p
+ (senf::PacketInterpreter<OtherPacket>::create(10u));
+ senf::PacketInterpreter<OtherPacket>::ptr p2
+ (senf::PacketInterpreter<OtherPacket>::createBefore(p));
+
+ BOOST_CHECK_EQUAL( p2->data().size(), 18u );
+ BOOST_CHECK_EQUAL( p->data().size(), 10u );
+
+ senf::PacketInterpreter<OtherPacket>::ptr p3
+ (senf::PacketInterpreter<OtherPacket>::createBefore(
+ p,senf::PacketInterpreterBase::noinit));
+
+ BOOST_CHECK_EQUAL( p3->data().size(), 10u );
+ }
+
+}
+
+// fields() ist tested in DefaultBundle/EthernetPacket.test.cc
+// initSize() and initHeadSize() are already tested indirectly above
+
+BOOST_AUTO_UNIT_TEST(packetInterpreter_factory)
+{
+ senf::PacketInterpreterBase::byte data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ senf::PacketInterpreterBase::factory_t factory (
+ senf::PacketInterpreter<OtherPacket>::factory());
+
+ BOOST_CHECK( ! senf::PacketInterpreterBase::no_factory() );
+ BOOST_REQUIRE( factory );
+
+ BOOST_CHECK( factory->create()->is<OtherPacket>() );
+ BOOST_CHECK_EQUAL( factory->create()->data().size(), 8u );
+ BOOST_CHECK_EQUAL( factory->create(senf::PacketInterpreterBase::noinit)->data().size(), 0u );
+ BOOST_CHECK_EQUAL( factory->create(12u)->data().size(), 12u );
+ BOOST_CHECK_EQUAL(
+ factory->create(4u, senf::PacketInterpreterBase::noinit)->data().size(), 4u );
+ BOOST_CHECK_EQUAL( factory->create(data)->data().size(), 6u );
+
+ {
+ senf::PacketInterpreter<VoidPacket>::ptr p
+ (senf::PacketInterpreter<VoidPacket>::create());
+
+ BOOST_CHECK_EQUAL( p->data().size(), 0u);
+ BOOST_CHECK( factory->createAfter(p)->is<OtherPacket>() );
+ BOOST_REQUIRE( p->next() );
+ BOOST_CHECK( ! p->next()->next() );
+
+ BOOST_CHECK_EQUAL( factory->createAfter(p)->data().size(), 8u );
+ BOOST_CHECK_EQUAL( p->data().size(), 8u );
+ BOOST_CHECK( ! p->next()->next() );
+
+ BOOST_CHECK_EQUAL(
+ factory->createAfter(p, senf::PacketInterpreterBase::noinit)->data().size(), 0u );
+ BOOST_CHECK_EQUAL( p->data().size(), 0u );
+ BOOST_CHECK( ! p->next()->next() );
+
+ BOOST_CHECK_EQUAL( factory->createAfter(p,12u)->data().size(), 12u );
+ BOOST_CHECK_EQUAL( p->data().size(), 12u );
+ BOOST_CHECK( ! p->next()->next() );
+
+ BOOST_CHECK_EQUAL(
+ factory->createAfter(p,4u, senf::PacketInterpreterBase::noinit)->data().size(), 4u );
+ BOOST_CHECK_EQUAL( p->data().size(), 4u );
+ BOOST_CHECK( ! p->next()->next() );
+
+ BOOST_CHECK_EQUAL( factory->createAfter(p, data)->data().size(), 6u );
+ BOOST_CHECK_EQUAL( p->data().size(), 6u );
+ BOOST_CHECK( ! p->next()->next() );
+ }
+
+ {
+ senf::PacketInterpreter<VoidPacket>::ptr p
+ (senf::PacketInterpreter<VoidPacket>::create(4u));
+
+ BOOST_CHECK_EQUAL( factory->createBefore(p)->data().size(), 12u );
+ BOOST_REQUIRE( p->prev() );
+ BOOST_CHECK( ! p->prev()->prev() );
+ BOOST_CHECK_EQUAL( p->prev()->data().size(), 12u );
+
+ BOOST_CHECK_EQUAL(
+ factory->createBefore(p,senf::PacketInterpreterBase::noinit)->data().size(), 4u );
+ BOOST_REQUIRE( p->prev() );
+ BOOST_CHECK( ! p->prev()->prev() );
+ BOOST_CHECK_EQUAL( p->prev()->data().size(), 4u );
+ }
+
+ {
+ senf::PacketInterpreter<VoidPacket>::ptr p
+ (senf::PacketInterpreter<VoidPacket>::create(12u));
+
+ senf::PacketInterpreterBase::ptr p2 (p->parseNextAs(factory));
+ BOOST_CHECK( p2->is<OtherPacket>() );
+ BOOST_CHECK( ! p2->is<VoidPacket>() );
+ BOOST_CHECK_EQUAL( boost::size(*p2->nextPacketRange()), 4u );
+ }
+
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketParser inline non-template implementation */
+
+// Custom includes
+#include <iterator>
+#include "PacketData.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketParserBase
+
+prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::i()
+ const
+{
+ return i_;
+}
+
+prefix_ senf::PacketParserBase::state_type senf::PacketParserBase::state()
+ const
+{
+ return data_;
+}
+
+prefix_ senf::PacketData & senf::PacketParserBase::data()
+ const
+{
+ return * data_;
+}
+
+prefix_ void senf::PacketParserBase::init()
+ const
+{}
+
+////////////////////////////////////////
+// protected members
+
+prefix_ senf::PacketParserBase::PacketParserBase(data_iterator i, state_type s)
+ : i_ (i), data_ (s)
+{}
+
+prefix_ senf::PacketParserBase::PacketParserBase(data_iterator i, state_type s,
+ size_type size)
+ : i_ (i), data_ (s)
+{
+ validate(size);
+}
+
+prefix_ bool senf::PacketParserBase::check(size_type size)
+{
+ return size <= size_type(std::distance(i(),end()));
+}
+
+prefix_ void senf::PacketParserBase::validate(size_type size)
+{
+ if (! check(size))
+ throw TruncatedPacketException();
+}
+
+////////////////////////////////////////
+// private members
+
+prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::end()
+{
+ return data_->end();
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
-// Copyright (C) 2007
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
// Stefan Bund <g0dil@berlios.de>
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief IpV6Extensions non-inline template implementation */
+ \brief PacketParser non-inline template implementation */
-//#include "IpV6Extensions.ih"
+#include "PacketParser.ih"
// Custom includes
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
-template <class Arg>
-prefix_ senf::IpV6Extension_Fragment::IpV6Extension_Fragment(Arg const & arg)
- : Packet(arg)
-{}
+template <class Parser>
+prefix_ typename boost::enable_if<
+ boost::is_base_of<senf::PacketParserBase, Parser>,
+ Parser >::type senf::operator<<(Parser target, Parser source)
+{
+ PacketParserBase::size_type target_sz (bytes(target));
+ PacketParserBase::size_type source_sz (bytes(source));
+ SafePacketParser<Parser> safe_target (target);
+ if (target_sz > source_sz)
+ target.data().erase(boost::next(target.i(),source_sz),boost::next(target.i(),target_sz));
+ else if (target_sz < source_sz)
+ target.data().insert(boost::next(target.i(),target_sz),source_sz-target_sz,0u);
+ Parser new_target (*safe_target);
+ std::copy( source.i(), boost::next(source.i(),source_sz),
+ PacketParserBase::data_iterator(new_target.i()) );
+ return new_target;
+}
///////////////////////////////ct.e////////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketParser inline template implementation */
+
+#include "PacketParser.ih"
+
+// Custom includes
+#include "PacketData.hh"
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketParserBase
+
+template <class Parser>
+prefix_ Parser senf::PacketParserBase::parse(data_iterator i)
+ const
+{
+ return Parser(i,state());
+}
+
+template <class Parser>
+prefix_ Parser senf::PacketParserBase::parse(size_type n)
+ const
+{
+ return Parser(boost::next(i(),n),state());
+}
+
+prefix_ void senf::PacketParserBase::defaultInit()
+ const
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// namespace members
+
+template <class Parser>
+prefix_ senf::PacketParserBase::size_type senf::bytes(Parser p)
+{
+ return detail::packetParserSize(p,0);
+}
+
+template <class Parser, class Value>
+prefix_ typename boost::enable_if_c <
+ boost::is_base_of<senf::PacketParserBase, Parser>::value
+ && ! boost::is_base_of<senf::PacketParserBase, Value>::value,
+ Parser >::type senf::operator<<(Parser target, Value const & value)
+{
+ target.value(value);
+ return target;
+}
+
+template <class Parser>
+prefix_ senf::PacketParserBase::size_type
+senf::detail::packetParserSize(Parser p, int, Parser_TakeNum<Parser::fixed_bytes> *)
+{
+ return Parser::fixed_bytes;
+}
+
+template <class Parser>
+prefix_ senf::PacketParserBase::size_type senf::detail::packetParserSize(Parser p, ...)
+{
+ return p.bytes();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::SafePacketParser<Parser>
+
+template <class Parser>
+prefix_ senf::SafePacketParser<Parser>::SafePacketParser()
+ : i_()
+{}
+
+template <class Parser>
+prefix_ senf::SafePacketParser<Parser>::SafePacketParser(Parser parser)
+ : parser_(parser), i_(parser)
+{}
+
+template <class Parser>
+prefix_ senf::SafePacketParser<Parser> & senf::SafePacketParser<Parser>::operator=(Parser parser)
+{
+ parser_ = parser;
+ i_ = parser;
+ return *this;
+}
+
+template <class Parser>
+prefix_ Parser senf::SafePacketParser<Parser>::operator*()
+ const
+{
+ BOOST_ASSERT( i_ );
+ parser_->i_ = PacketParserBase::data_iterator(i_);
+ return *parser_;
+}
+
+template <class Parser>
+prefix_ Parser const * senf::SafePacketParser<Parser>::operator->()
+ const
+{
+ BOOST_ASSERT( i_ );
+ parser_->i_ = PacketParserBase::data_iterator(i_);
+ return & (*parser_);
+}
+
+template <class Parser>
+prefix_ bool senf::SafePacketParser<Parser>::boolean_test()
+ const
+{
+ return i_;
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketParser public header */
+
+/** \defgroup packetparser The PacketParser facility
+
+ The PacketParser facility provides a framework to implement very lightweight classes which parse
+ the raw content of a packet into meaningful values. PacketParsers are always passed around by
+ value, they can be understood as pointers into the data structure with added type information
+ providing parsing functions.
+
+ Parsers are built hirarchically. A high-level parser will return other parsers when returning
+ some element (Example: Asking an EthernetParser for the ethertype field by calling the parsers
+ \c type() member will return an UInt16 parser). The lowest level building blocks then return the
+ values. This hierarchical structure greatly simplifies building complex parsers.
+
+ Every parser is derived from senf::PacketParserBase. This parser provides the necessary
+ housekeeping information and provides the parsers with access to the data.
+
+ The PacketParser facility predefines several parsers to be used as building blocks in defining
+ more complex parsers (integer parsers, several parsers for repetitive constructs)
+ */
+
+#ifndef HH_PacketParser_
+#define HH_PacketParser_ 1
+
+// Custom includes
+#include <boost/utility/enable_if.hpp>
+#include <boost/type_traits.hpp>
+#include <boost/optional.hpp>
+#include "Utils/SafeBool.hh"
+#include "PacketTypes.hh"
+#define HH_PacketData_DeclOnly
+#include "PacketData.hh"
+#undef HH_PacketData_DeclOnly
+
+#include "PacketParser.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ /** \brief Parser Baseclass
+
+ To implement a packet parser, you need to derive from PacketParserBase and implement several
+ required members. There are two ways how to do this.
+ \li If the parser just consists of a simple sequence of consecutive fields, the
+ SENF_PACKET_PARESR_DEFINE_FIELDS and SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros
+ provide a simple an convenient way to define the packet
+ \li In more complex cases, you need to implement the necessary members manually.
+
+ The following example documents the interface (which must be) provided by a parser.
+ \code
+ struct FooParser : public PacketParserBase
+ {
+ FooParser(data_iterator i, state_type s) : PacketParserBase(i,s) {}
+
+ // If this parser has a fixed size, you must define this size here This definition
+ // allows the parser to be used within the list, vector and array parsers static
+ static const size_type fixed_bytes = some_constant_size;
+
+ // If the parser does not have a fixed size, you must implement the bytes() member to
+ // return the size. ONLY EVER DEFINE ONE OF fixed_bytes OR bytes().
+ size_type bytes() const;
+
+ // If you define bytes(), you also need to define the init_bytes. This is the number
+ // of bytes to allocate when creating a new object
+ static const size_type init_bytes = some_constant_size;
+
+ // You also mey define an init() member. This will be called to initialize a newly
+ // created data object. The default implementation just does nothing.
+ void init() const;
+
+ // ////////////////////////////////////////////////////////////////////////
+
+ // Add here members returning (sub-)parsers for the fields. The 'parse' member is
+ // used to construct the sub-parsers. This member either takes an iterator to the
+ // data to be parsed or just an offset in bytes.
+
+ senf::Parse_UInt16 type() const { return parse<Parse_UInt16>( 0 ); }
+ senf::Parse_UInt16 size() const { return parse<Parse_UInt16>( 2 ); }
+ };
+ \endcode
+
+ You should never call the \c bytes() member of a parser directly. Instead you should use the
+ freestanding senf::bytes() functon. This function will return the correct size even for
+ fixed-size parsers. You may access \c fixed_bytes directly, however be aware that this will
+ restrict your code to fixed size parsers (which depending on the circumstances may be
+ exactly what you want).
+
+ In the same way, dont access \c init_bytes directly, always use the senf::init_bytes
+ metafunction class which will correctly support fixed size parsers.
+
+ \ingroup packetparser
+ */
+ class PacketParserBase
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef detail::packet::iterator data_iterator;
+ typedef detail::packet::size_type size_type;
+ typedef detail::packet::difference_type difference_type;
+ typedef detail::packet::byte byte;
+ typedef PacketData * state_type;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // no default constructor
+ // default copy
+ // default destructor
+ // no conversion constructors
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ data_iterator i() const;
+ state_type state() const;
+ PacketData & data() const;
+
+ void init() const;
+
+ protected:
+ PacketParserBase(data_iterator i, state_type s);
+ PacketParserBase(data_iterator i, state_type s, size_type size);
+
+ bool check(size_type size);
+ void validate(size_type size);
+
+ template <class Parser> Parser parse(data_iterator i) const;
+ template <class Parser> Parser parse(size_type n) const;
+
+ void defaultInit() const;
+
+ private:
+ data_iterator end();
+
+ data_iterator i_;
+ PacketData * data_;
+
+ template <class Parser> friend class SafePacketParser;
+ };
+
+ /** \brief Return raw size parsed by the given parser object
+
+ This function will either call <tt>p.bytes()</tt> or return <tt>Parser::fixed_bytes</tt>
+ depending on the type of parser.
+
+ The value returned does \e not take into account the amount of data actually available. So
+ you always need to validate this value against the packet size if you directly access the
+ data. The standard low-level parses all do this check automatically to guard against
+ malformed packets.
+
+ \param[in] p Parser object to check
+ \returns number of bytes this parser expects to parser
+ \ingroup packetparser
+ */
+ template <class Parser>
+ PacketParserBase::size_type bytes(Parser p);
+
+ namespace detail { template <class Parser> class ParserInitBytes; }
+
+ /** \brief Return number of bytes to allocate to new object of given type
+
+ This metafcuntion is called like
+ \code
+ senf::init_bytes<SomeParser>::value
+ \endcode
+
+ This expression evaluates to a compile-time constant itegral expression of type
+ senf::PacketParserBase::size_type. This metafunction will return \c Parser::fixed_bytes or
+ \c Parser::init_bytes depending on the type of parser.
+
+ \param[in] Parser Parser to return init_bytes for
+ \returns Number of bytes to allocate to the new object
+ \ingroup packetparser
+ */
+ template <class Parser>
+ struct init_bytes : public detail::ParserInitBytes<Parser>
+ {};
+
+ template <class Parser>
+ typename boost::enable_if<
+ boost::is_base_of<PacketParserBase, Parser>,
+ Parser >::type
+ operator<<(Parser target, Parser source);
+
+ template <class Parser, class Value>
+ typename boost::enable_if_c <
+ boost::is_base_of<PacketParserBase, Parser>::value
+ && ! boost::is_base_of<PacketParserBase, Value>::value,
+ Parser >::type
+ operator<<(Parser target, Value const & value);
+
+ /** \defgroup packetparsermacros Helper macros for defining new packet parsers
+
+ To simplify the definition of simple packet parsers, several macros are provided. Before
+ using these macros you should familarize yourself with the packet parser interface as
+ described in senf::PacketParserBase.
+
+ These macros simplify providing the above defined interface. A typical packet declaration
+ using these macros has the following form (This is a concrete example from the definition of
+ the ethernet packet in <tt>DefaultBundle//EthernetPacket.hh</tt>)
+ \code
+ struct Parse_EthVLan : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(Parse_EthVLan);
+
+ // ////////////////////////////////////////////////////////////////////////
+
+ typedef senf::Parse_UIntField < 0, 3 > Parse_Priority;
+ typedef senf::Parse_Flag < 3 > Parse_CFI;
+ typedef senf::Parse_UIntField < 4, 16 > Parse_VLanId;
+ typedef senf::Parse_UInt16 Parse_Type;
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((OverlayField)( priority, Parse_Priority ))
+ ((OverlayField)( cfi, Parse_CFI ))
+ ((Field )( vlanId, Parse_VLanId ))
+ ((Field )( type, Parse_Type ))
+ );
+ };
+ \endcode
+
+ The macros take care of the following:
+ \li They define the accessor functions returning parsers of the given type.
+ \li They automatically calculate the offset of the fields from the preceding fields.
+ \li The macros provide a definition for \c init()
+ \li The macros define the \c bytes(), \c fixed_bytes and \c init_bytes members as needed.
+
+ You may define either a fixed or a dynamically sized parser. Fixed size parsers are defined
+ using \ref SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS, dynamically sized parsers are defined
+ using \ref SENF_PACKET_PARSER_DEFINE_FIELDS. The different members are implemented such
+ that:
+
+ \li The needed parser constructor is defined
+ \li \c init() calls \c defaultInit(). \c defaultInit() is defined to call \c init() on each
+ of the fields.
+ \li \c bytes() (on dynamically sized parser) respectively \c fixed_bytes (on fixed size
+ parsers) is defined to return the sum of the sizes of all fields.
+ \li On dynamically sized parsers, \c init_bytes is defined to return the sum of the
+ \c init_size's of all fields
+
+ The central definition macros are \ref SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS and \ref
+ SENF_PACKET_PARSER_DEFINE_FIELDS. The argument to both has the same structure. It is a
+ (boost preprocessor style) sequence of field definitions where each field definition
+ provides the builder macro to use and the name and type of the field to define:
+ \code
+ SENF_PACKET_PARSER_DEFINE[_FIXED]_FIELDS(
+ (( <builder> )( <name>, <type> ))
+ ...
+ )
+ \endcode
+
+ The \a builder argument selects, how the field is defined
+ \li <tt>Field</tt> defines a field and increments the current position by the size of the
+ field
+ \li <tt>OverlayField</tt> defines a field like <tt>Field</tt> but does \e not increment the
+ position. In the above example, this is used to overlay the different bitfield parsers:
+ All overlaying bitfield parser except the last one (the one with the highest bit
+ numbers) is marked as OverlayField.
+
+ The \a name argument defines the name of the accessor method.
+
+ The \a type argument is the parser to return for that field. Since none of the arguments may
+ contain a komma, <em>This argument cannot be a template</em>. Always use typedefs to access
+ tempalte parsers as shown above.
+
+ The \ref SENF_PACKET_PARSER_INIT makro defines the constructor and the \c init() member. If
+ you want to provide your own \c init() implementation, use \ref
+ SENF_PACKET_PARSER_NO_INIT. The first statement in your init method should probably to call
+ \c defaultInit(). This will call the \c init() member of all the fields. Afterwards you can
+ set up the field values as needed:
+ \code
+ struct SomePacket : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_NO_INIT(SomePacket);
+
+ typedef senf::Parse_UInt8 Parse_Type;
+ typedef senf::Parse_Vector< senf::Parse_UInt32,
+ senf::SimpleVectorSizer<senf::Parse_UInt16>
+ > Parse_Elements;
+
+ SENF_PACKET_PARSER_DEFINE_FIELDS(
+ ((Field)( type, Parse_Type ))
+ ((Field)( elements, Parse_Elements ))
+ );
+
+ void init() const {
+ defaultInit();
+ type() = 0x01;
+ elements().push_back(0x01020304u);
+ }
+ }
+ \endcode
+
+ \ingroup packetparser
+ */
+
+ /** \brief Define initialization members of a parser
+
+ This macro defines the packet parser constructor and the \c init() member. \c init() is
+ defined to just call \c defaultInit() which is defined by the other macros to call \c init()
+ on each of the parsers fields.
+
+ \ingroup packetparsermacros
+ \hideinitializer
+ */
+# define SENF_PACKET_PARSER_INIT(name) \
+ name(data_iterator i, state_type s) : senf::PacketParserBase(i,s) {} \
+ void init() const { defaultInit(); }
+
+ /** \brief Define initialization mebers of a parser except init()
+
+ This macro is like SENF_PACKET_PARSER_INIT but does \e not define \c init(). This allows you
+ to provide your own implementation. You should call \c defaultInit() first before
+ initializing your data fields.
+
+ \ingroup packetparsermacros
+ \hideinitializer
+ */
+# define SENF_PACKET_PARSER_NO_INIT(name) \
+ name(data_iterator i, state_type s) : senf::PacketParserBase(i,s) {}
+
+ /** \brief Define fields for a dynamically sized parser
+
+ Define the fields as specified in \a fields. This macro supports dynamically sized
+ subfields, the resulting parser will be dynamically sized.
+
+ \ingroup packetparsermacros
+ \hideinitializer
+ */
+# define SENF_PACKET_PARSER_DEFINE_FIELDS(fields) \
+ SENF_PACKET_PARSER_I_DEFINE_FIELDS(fields)
+
+ /** \brief Define fields for a fixed size parser
+
+ Define the fields as specified in \a fields. This macro only supports fixed size
+ subfields, the resulting parser will also be a fixed size parser.
+
+ \ingroup packetparsermacros
+ \hideinitializer
+ */
+# define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(fields) \
+ SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(fields)
+
+ struct VoidPacketParser
+ : public PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(VoidPacketParser);
+ };
+
+ /** \brief
+ */
+ template <class Parser>
+ class SafePacketParser
+ : public SafeBool< SafePacketParser<Parser> >
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // default default constructor
+ // default copy constructor
+ // default copy assignment
+ // default destructor
+ SafePacketParser();
+
+ // conversion constructors
+ SafePacketParser(Parser parser);
+
+ SafePacketParser & operator=(Parser parser);
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ Parser operator*() const;
+ Parser const * operator->() const;
+ bool boolean_test() const;
+
+ protected:
+
+ private:
+ mutable boost::optional<Parser> parser_;
+ senf::safe_data_iterator i_;
+ };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "PacketParser.cci"
+#include "PacketParser.ct"
+#include "PacketParser.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketParser internal header */
+
+#ifndef IH_PacketParser_
+#define IH_PacketParser_ 1
+
+// Custom includes
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace detail {
+
+ // PLEASE don't add this to doxygen ... it just looks to weird and does not help ...
+
+# ifndef DOXYGEN
+
+ template <PacketParserBase::size_type i>
+ struct Parser_TakeNum {};
+
+ template <class Parser>
+ PacketParserBase::size_type packetParserSize(
+ Parser p, int, Parser_TakeNum<Parser::fixed_bytes> * = 0);
+
+ template <class Parser>
+ PacketParserBase::size_type packetParserSize(Parser p, ...);
+
+ template <unsigned n> struct ParserInitBytes_RV { char _[16][n]; };
+
+ template <class Parser>
+ ParserInitBytes_RV<1> ParserInitBytes_Choose_(Parser_TakeNum<Parser::init_bytes> *);
+
+ template <class Parser>
+ ParserInitBytes_RV<2> ParserInitBytes_Choose_(...);
+
+ template <class Parser, unsigned size>
+ struct ParserInitBytes_Choose
+ : public boost::integral_constant<PacketParserBase::size_type, Parser::init_bytes> {};
+
+ template <class Parser>
+ struct ParserInitBytes_Choose<Parser, sizeof(ParserInitBytes_RV<2>)>
+ : public boost::integral_constant<PacketParserBase::size_type, Parser::fixed_bytes> {};
+
+ template <class Parser>
+ struct ParserInitBytes
+ : public ParserInitBytes_Choose<Parser, sizeof(ParserInitBytes_Choose_<Parser>(0))> {};
+
+# endif
+
+}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+# // Copyright (C) 2007
+# // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+# // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+# // Stefan Bund <g0dil@berlios.de>
+# //
+# // 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 2 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, write to the
+# // Free Software Foundation, Inc.,
+# // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# /** \file
+# \brief PacketParser Boost.Preprocesser definitions */
+#
+# if !defined(MPP_PacketParser_)
+# define MPP_PacketParser_ 1
+#
+# // Custom includes
+# include <boost/preprocessor/seq/for_each_i.hpp>
+# include <boost/preprocessor/seq/for_each.hpp>
+# include <boost/preprocessor/seq/size.hpp>
+# include <boost/preprocessor/cat.hpp>
+# include <boost/preprocessor/inc.hpp>
+# include <boost/preprocessor/tuple/elem.hpp>
+# include <boost/preprocessor/facilities/expand.hpp>
+#
+# ///////////////////////////////mpp.p///////////////////////////////////////
+#
+# define SENF_PACKET_PARSER_I_UNWRAP(n,elt) (n,SENF_PACKET_PARSER_I_UNWRAP_1 elt)
+# define SENF_PACKET_PARSER_I_UNWRAP_1(x) x,SENF_PACKET_PARSER_I_UNWRAP_2
+# define SENF_PACKET_PARSER_I_UNWRAP_2(x,y) x,y
+#
+# define SENF_PACKET_PARSER_I_GET_NAME(elt) SENF_PACKET_PARSER_I_GET_NAME_1 elt
+# define SENF_PACKET_PARSER_I_GET_NAME_1(x) SENF_PACKET_PARSER_I_GET_NAME_2
+# define SENF_PACKET_PARSER_I_GET_NAME_2(name,type) name
+#
+# define SENF_PACKET_PARSER_I_GET_TYPE(elt) SENF_PACKET_PARSER_I_GET_TYPE_1 elt
+# define SENF_PACKET_PARSER_I_GET_TYPE_1(x) SENF_PACKET_PARSER_I_GET_TYPE_2
+# define SENF_PACKET_PARSER_I_GET_TYPE_2(name,type) type
+#
+# define SENF_PACKET_PARSER_I_DEFINE_INIT_C(_0,_1,elt) \
+ SENF_PACKET_PARSER_I_GET_NAME(elt) ().init();
+#
+# define SENF_PACKET_PARSER_I_DEFINE_INIT(fields) \
+ void defaultInit() const { \
+ BOOST_PP_SEQ_FOR_EACH( SENF_PACKET_PARSER_I_DEFINE_INIT_C, _, fields) \
+ }
+#
+# define SENF_PACKET_PARSER_I_FIELD_DISPATCH(n,t,name,type) \
+ SENF_PACKET_PARSER_I_ ## t(n,name,type)
+#
+# define SENF_PACKET_PARSER_I_FIELD_C(_0,_1,n,elt) \
+ BOOST_PP_EXPAND( \
+ SENF_PACKET_PARSER_I_FIELD_DISPATCH SENF_PACKET_PARSER_I_UNWRAP(n,elt))
+#
+# define SENF_PACKET_PARSER_I_INITSIZE_C(_0,_1,n,elt) \
+ BOOST_PP_IF(n,+,) senf::init_bytes< SENF_PACKET_PARSER_I_GET_TYPE(elt) >::value
+#
+# define SENF_PACKET_PARSER_I_DEFINE_FIELDS(fields) \
+ size_type offset_0_() const { return 0; } \
+ BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_FIELD_C, _, fields) \
+ size_type bytes() const { \
+ return BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_SEQ_SIZE(fields),_)) (); \
+ } \
+ SENF_PACKET_PARSER_I_DEFINE_INIT(fields) \
+ static const size_type init_bytes = \
+ BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_INITSIZE_C, _, fields) ;
+#
+# define SENF_PACKET_PARSER_I_FIXED_FIELD_DISPATCH(n,t,name,type) \
+ SENF_PACKET_PARSER_I_FIXED_ ## t(n,name,type)
+#
+# define SENF_PACKET_PARSER_I_FIXED_FIELD_C(_0,_1,n,elt) \
+ BOOST_PP_EXPAND( \
+ SENF_PACKET_PARSER_I_FIXED_FIELD_DISPATCH SENF_PACKET_PARSER_I_UNWRAP(n,elt))
+#
+# define SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(fields) \
+ static const size_type offset_0_ = 0; \
+ BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_FIXED_FIELD_C, _, fields) \
+ static const size_type fixed_bytes = \
+ BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_SEQ_SIZE(fields),_)); \
+ SENF_PACKET_PARSER_I_DEFINE_INIT(fields)
+#
+# ///////////////////////////////////////////////////////////////////////////
+# // Definition of the field types
+#
+# define SENF_PACKET_PARSER_I_Field(n,name,type) \
+ type name () const { \
+ return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () ); \
+ } \
+ size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () const { \
+ return BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () + senf::bytes( name () ); \
+ }
+#
+# define SENF_PACKET_PARSER_I_FIXED_Field(n,name,type) \
+ type name () const { \
+ return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) ); \
+ } \
+ static const size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) = \
+ BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) + type::fixed_bytes;
+#
+# define SENF_PACKET_PARSER_I_OverlayField(n,name,type) \
+ type name () const { \
+ return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () ); \
+ } \
+ size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () const { \
+ return BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) (); \
+ }
+#
+# define SENF_PACKET_PARSER_I_FIXED_OverlayField(n,name,type) \
+ type name () const { \
+ return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) ); \
+ } \
+ static const size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) = \
+ BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_));
+#
+# ///////////////////////////////mpp.e///////////////////////////////////////
+# endif
+#
+# \f
+# // Local Variables:
+# // mode: c++
+# // fill-column: 100
+# // c-file-style: "senf"
+# // indent-tabs-mode: nil
+# // ispell-local-dictionary: "american"
+# // compile-command: "scons -u test"
+# // End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketParser.test unit tests */
+
+//#include "PacketParser.test.hh"
+//#include "PacketParser.test.ih"
+
+// Custom includes
+#include "PacketParser.hh"
+#include "PacketInterpreter.hh"
+#include "PacketType.hh"
+#include "ParseInt.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase {};
+
+ struct SimpleParser : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(SimpleParser);
+
+ using senf::PacketParserBase::check;
+ using senf::PacketParserBase::validate;
+ };
+
+ struct FooParser : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(FooParser);
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((Field)( name, senf::Parse_UInt16 ))
+ ((Field)( id, senf::Parse_Int32 )) );
+ };
+
+ struct BarParser : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(BarParser);
+
+ SENF_PACKET_PARSER_DEFINE_FIELDS(
+ ((Field)( name, senf::Parse_UInt16 ))
+ ((Field)( id, senf::Parse_Int32 )) );
+ };
+}
+
+BOOST_AUTO_UNIT_TEST(packetParserBase)
+{
+ senf::PacketInterpreter<VoidPacket>::ptr pi (senf::PacketInterpreter<VoidPacket>::create(6u));
+ SimpleParser p (pi->data().begin(),&pi->data());
+
+ BOOST_CHECK( pi->data().begin() == p.i() );
+ BOOST_CHECK( p.check(6u) );
+ BOOST_CHECK( ! p.check(7u) );
+ BOOST_CHECK_NO_THROW( p.validate(6u) );
+ BOOST_CHECK_THROW( p.validate(7u), senf::TruncatedPacketException );
+
+ // ?? Why the heck do I need the +0? I get an 'undefined symbol FooParser::fixed_bytes'
+ // otherwise ...
+ BOOST_CHECK_EQUAL( FooParser::fixed_bytes+0, 6u );
+ BOOST_CHECK_EQUAL( BarParser(pi->data().begin(),&pi->data()).bytes(), 6u );
+ BOOST_CHECK_EQUAL( senf::bytes(senf::Parse_UInt16(pi->data().begin(),&pi->data())), 2u );
+ BOOST_CHECK_EQUAL( senf::bytes(FooParser(pi->data().begin(),&pi->data())), 6u );
+ BOOST_CHECK_EQUAL( senf::bytes(BarParser(pi->data().begin(),&pi->data())), 6u );
+
+ BOOST_CHECK_EQUAL( senf::init_bytes<FooParser>::value, 6u );
+ BOOST_CHECK_EQUAL( senf::init_bytes<BarParser>::value, 6u );
+}
+
+BOOST_AUTO_UNIT_TEST(safePacketParser)
+{
+ senf::PacketInterpreter<VoidPacket>::ptr pi (senf::PacketInterpreter<VoidPacket>::create(6u));
+ senf::SafePacketParser<senf::Parse_UInt16> p;
+
+ BOOST_CHECK( !p );
+
+ p = senf::Parse_UInt16(pi->data().begin(),&pi->data());
+
+ BOOST_CHECK( p );
+ (*p) = 0x1234u;
+
+ BOOST_CHECK_EQUAL( (*p), 0x1234u );
+ BOOST_CHECK_EQUAL( p->data()[0], 0x12u );
+
+ p->data().resize(1024u);
+ BOOST_CHECK_EQUAL( (*p), 0x1234u );
+ (*p) = 0x2345u;
+ BOOST_CHECK_EQUAL( p->data()[0], 0x23u );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline non-template funPacketRegistry.ons
+/** \file
+ \brief PacketRegistry non-inline non-template implementation */
#include "PacketRegistry.hh"
#include "PacketRegistry.ih"
// Custom includes
+//#include "PacketRegistry.mpp"
#define prefix_
-///////////////////////////////PacketRegistry..p////////////////////////////////////////
+///////////////////////////////cc.p////////////////////////////////////////
-senf::impl::PkReg_EntryImpl<senf::DataPacket>
- senf::impl::pkreg_dataEntry;
+prefix_ senf::PkReg_Entry::~PkReg_Entry()
+{}
-///////////////////////////////PacketRegistry..e////////////////////////////////////////
+///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
+//#include "PacketRegistry.mpp"
\f
// Local Variables:
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
// Custom includes
#include <iostream>
-#include "Utils/TypeInfo.hh"
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
+template <class PacketType>
+prefix_ senf::PacketInterpreterBase::factory_t senf::detail::PkReg_EntryImpl<PacketType>::factory()
+ const
+{
+ return PacketInterpreter<PacketType>::factory();
+}
+
template <class KeyType>
-template <class OtherPacket>
-prefix_ void senf::impl::PacketRegistryImpl<KeyType>::registerPacket(key_t key)
+template <class PacketType>
+prefix_ void senf::detail::PacketRegistryImpl<KeyType>::registerPacket(key_t key)
{
+ bool isUnique (
+ registry_.insert(
+ std::make_pair(key, Entry_ptr(new detail::PkReg_EntryImpl<PacketType>()))).second);
// If this assertion fails, a Packet was registered with an already known key
- BOOST_ASSERT( registry_.insert(std::make_pair(
- key, Entry_ptr(new impl::PkReg_EntryImpl<OtherPacket>()))).second );
+ BOOST_ASSERT( isUnique );
+ bool isNew (
+ reverseRegistry_.insert(
+ std::make_pair(senf::typeIdValue<PacketType>(), key)).second);
// If this assertion fails, the same Packet was registered with two different keys
- BOOST_ASSERT( reverseRegistry_.insert(
- std::make_pair(senf::typeIdValue<OtherPacket>(), key)).second );
+ BOOST_ASSERT( isNew );
}
template <class KeyType>
-prefix_ typename senf::impl::PacketRegistryImpl<KeyType>::key_t
-senf::impl::PacketRegistryImpl<KeyType>::key(senf::TypeIdValue const & type)
+prefix_ typename senf::detail::PacketRegistryImpl<KeyType>::key_t
+senf::detail::PacketRegistryImpl<KeyType>::key(senf::TypeIdValue const & type)
{
typename ReversePacketMap::iterator i (reverseRegistry_.find(type));
if (i==reverseRegistry_.end())
- throw PacketTypeNotRegistered();
+ throw PacketTypeNotRegisteredException();
return i->second;
}
-template <class OtherPacket>
-prefix_ void
-senf::impl::PkReg_EntryImpl<OtherPacket>::registerInterpreter(Packet const * p,
- Packet::iterator b,
- Packet::iterator e)
+template <class KeyType>
+prefix_ boost::optional<typename senf::detail::PacketRegistryImpl<KeyType>::key_t>
+senf::detail::PacketRegistryImpl<KeyType>::key(senf::TypeIdValue const & type, bool)
{
- p->template registerInterpreter<OtherPacket>(b,e);
+ typename ReversePacketMap::iterator i (reverseRegistry_.find(type));
+ if (i==reverseRegistry_.end())
+ return boost::optional<key_t>();
+ return i->second;
}
-template <class OtherPacket>
-prefix_ senf::Packet::ptr
-senf::impl::PkReg_EntryImpl<OtherPacket>::reinterpret(Packet * p)
+template <class KeyType>
+prefix_ typename senf::detail::PacketRegistryImpl<KeyType>::Entry const &
+senf::detail::PacketRegistryImpl<KeyType>::lookup(key_t key)
{
- return p->template reinterpret<OtherPacket>();
+ typename PacketMap::iterator i (registry_.find(key));
+ if (i==registry_.end())
+ throw PacketTypeNotRegisteredException();
+ return *(i->second);
}
template <class KeyType>
-prefix_ typename senf::impl::PacketRegistryImpl<KeyType>::Entry *
-senf::impl::PacketRegistryImpl<KeyType>::lookup(key_t key)
+prefix_ typename senf::detail::PacketRegistryImpl<KeyType>::Entry const *
+senf::detail::PacketRegistryImpl<KeyType>::lookup(key_t key, bool)
{
typename PacketMap::iterator i (registry_.find(key));
if (i==registry_.end())
- return &impl::pkreg_dataEntry;
+ return 0;
return i->second.get();
}
template <class Tag>
-template <class InputIterator>
-prefix_ senf::Packet::ptr
-senf::PacketRegistry<Tag>::create(typename Tag::key_t key, InputIterator b,
- InputIterator e)
-{
- Packet::ptr p (Packet::create<DataPacket>(b,e));
- return registry().lookup(key)->reinterpret(p.get());
-}
-
-template <class Tag>
prefix_ typename senf::PacketRegistry<Tag>::Registry &
senf::PacketRegistry<Tag>::registry()
{
#include "PacketRegistry.ih"
// Custom includes
-#include "Packet.hh"
#define prefix_ inline
///////////////////////////////PacketRegistry..p///////////////////////////////////////
template <class Tag>
-template <class OtherPacket>
-prefix_ void senf::PacketRegistry<Tag>::registerPacket(typename Tag::key_t key)
+template <class PacketType>
+prefix_ senf::PacketRegistry<Tag>::RegistrationProxy<PacketType>::
+RegistrationProxy(typename Tag::key_t key)
{
- registry().registerPacket<OtherPacket>(key);
+ PacketRegistry<Tag>::template registerPacket<PacketType>(key);
}
template <class Tag>
-template <class OtherPacket>
-prefix_ senf::PacketRegistry<Tag>::RegistrationProxy<OtherPacket>::
-RegistrationProxy(typename Tag::key_t key)
+template <class PacketType>
+prefix_ void senf::PacketRegistry<Tag>::registerPacket(typename Tag::key_t key)
{
- PacketRegistry<Tag>::template registerPacket<OtherPacket>(key);
+ registry().registerPacket<PacketType>(key);
}
template <class Tag>
-template <class OtherPacket>
+template <class PacketType>
prefix_ typename Tag::key_t senf::PacketRegistry<Tag>::key()
{
- return registry().key(senf::typeIdValue<OtherPacket>());
+ return registry().key(senf::typeIdValue<PacketType>());
+}
+
+template <class Tag>
+template <class PacketType>
+prefix_ typename boost::optional<typename Tag::key_t> senf::PacketRegistry<Tag>::key(NoThrow_t)
+{
+ return registry().key(senf::typeIdValue<PacketType>(),true);
+}
+
+template <class Tag>
+prefix_ typename Tag::key_t senf::PacketRegistry<Tag>::key(Packet packet)
+{
+ return registry().key(packet.typeId());
}
-template <class KeyType>
-template <class OtherPacket>
-prefix_ void
-senf::impl::PacketRegistryImpl<KeyType>::registerInterpreter(Packet * p,
- Packet::iterator b,
- Packet::iterator e)
+template <class Tag>
+prefix_ typename Tag::key_t senf::PacketRegistry<Tag>::key(Packet packet, NoThrow_t)
{
- p->registerInterpreter<OtherPacket>(b,e);
+ return registry().key(packet.typeId(),true);
}
-template <class Tag, class Derived>
-prefix_ void
-senf::PacketRegistryMixin<Tag,Derived>::registerInterpreter(typename Tag::key_t key,
- Packet::iterator b,
- Packet::iterator e)
- const
+template <class Tag>
+prefix_ senf::PkReg_Entry const & senf::PacketRegistry<Tag>::lookup(typename Tag::key_t key)
+{
+ return registry().lookup(key);
+}
+
+template <class Tag>
+prefix_ senf::PkReg_Entry const * senf::PacketRegistry<Tag>::lookup(typename Tag::key_t key,
+ NoThrow_t)
{
- PacketRegistry<Tag>::registry().lookup(key)->registerInterpreter(
- static_cast<Derived const * const>(this),b,e);
+ return registry().lookup(key,true);
}
///////////////////////////////PacketRegistry..e///////////////////////////////////////
// Custom includes
#include <map>
#include <boost/utility.hpp> // for boost::noncopyable
-#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include "Utils/Exception.hh"
+#include "PacketInterpreter.hh"
#include "Packet.hh"
//#include "PacketRegistry.mpp"
namespace senf {
+ struct PkReg_Entry
+ : public intrusive_refcount
+ {
+ virtual ~PkReg_Entry();
+ virtual PacketInterpreterBase::factory_t factory() const = 0;
+ };
- namespace impl { template <class key> class PacketRegistryImpl; }
+ namespace detail { template <class Key> class PacketRegistryImpl; }
/** \brief Packet registration facility
public:
/** \brief Statically register a packet type in a PacketRegistry
*/
- template <class OtherPacket>
+ template <class PacketType>
struct RegistrationProxy
{
RegistrationProxy(typename Tag::key_t key);
/** \brief Register new packet type
- Register \c OtherPacket in the packet registry \c Tag
+ Register \c PacketType in the packet registry \c Tag
under the given \c key.
\par Preconditions:
any other packet class in this registry.
The Packet must not already be registered in the registry.
- \param OtherPacket packet to register
+ \param PacketType packet to register
\param key key of the packet
*/
- template <class OtherPacket>
+ template <class PacketType>
static void registerPacket(typename Tag::key_t key);
/** \brief Find key of a packet
- Return the key of \c OtherPacket as registered in the \c
+ Return the key of \c PacketType as registered in the \c
Tag registry
- \param OtherPacket packet of which the key is requested
+ \param PacketType packet of which the key is requested
\returns key of the packet
\throws PacketTypeNotRegistered if the packet type is not
found in the registry.
*/
- template <class OtherPacket>
+ template <class PacketType>
static typename Tag::key_t key();
- /** \brief Create new Packet
-
- \param key Key of packet type to create instance of
- \param b begin iterator argument to Packet::create()
- \param e end iterator argument to Packet::create()
- \returns new Instance of the packet type registered under
- key or DataPacket, if the key is not registered.
- */
- template <class InputIterator>
- static Packet::ptr create(typename Tag::key_t key, InputIterator b, InputIterator e);
+ template <class PacketType>
+ static typename boost::optional<typename Tag::key_t> key(NoThrow_t);
- private:
- typedef impl::PacketRegistryImpl<typename Tag::key_t> Registry;
- static Registry & registry();
+ static typename Tag::key_t key(Packet packet);
+ static typename Tag::key_t key(Packet packet, NoThrow_t);
- template <class T, class D> friend class PacketRegistryMixin;
- };
+ /** \brief Lookup a packet by it's key
- /** \brief Helper class for v_nextInterpreter implementations
+ Returns the packet registration registered under \a key in the \a Tag registry
- This class is a helper class which is to be inherited from in
- a packet facade which wants to register a new interpreter with
- the packet framework depending on a packet registry.
+ \param key Key of the packet registered
+ \returns Registration entry of the packet
+ \throws PacketTypeNotRegistered if the packet type is not found in the registry
+ */
+ static PkReg_Entry const & lookup(typename Tag::key_t key);
- This mixin class provides a new registerInterpreter
- implementation which can be used besides the methods provided
- by senf::Packet to add a new interpreter to the
- interpreter chain.
+ static PkReg_Entry const * lookup(typename Tag::key_t key, NoThrow_t);
- \code
- class SomePacket
- : public Packet,
- private PacketRegistryMixin<SomeTag,SomePacket>
- {
- using Packet::retgisterInterpreter;
- using PacketRegistryMixin<SomeTag,SomePacket>::registerInterpreter;
-
- virtual void v_nextInterpreter()
- {
- registerInterpreter(some_key_value, subpacket_begin, subpacket_end);
- }
- };
- \endcode
- This example is not complete, it only contains the parts
- concerned with PacketRegistryMixin.
- */
- template <class Tag, class Derived>
- class PacketRegistryMixin
- {
- protected:
- /** \brief add interpreter to interpreter chain
-
- This method is used by v_nextInterpreter() to add a new
- interpreter to the interpreter chain (see the Packet
- reference for more). Instead of specifying the type of
- packet to use as a template argument it is specified using
- the \c key value from the \c Tag registry
- */
- void registerInterpreter(typename Tag::key_t key,
- Packet::iterator b, Packet::iterator e) const;
+ private:
+ typedef detail::PacketRegistryImpl<typename Tag::key_t> Registry;
+ static Registry & registry();
};
- struct PacketTypeNotRegistered : public std::exception
+ struct PacketTypeNotRegisteredException : public std::exception
{ virtual char const * what() const throw() { return "packet type not registered"; } };
}
#define IH_PacketRegistryImpl_ 1
// Custom includes
-#include "Packet.hh"
-#include "DataPacket.hh"
+#include <boost/intrusive_ptr.hpp>
#include "typeidvalue.hh"
///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
+namespace detail {
-namespace impl {
-
- struct PkReg_Entry {
- virtual ~PkReg_Entry() {}
- virtual void registerInterpreter(Packet const * p,
- Packet::iterator b, Packet::iterator e) = 0;
- virtual Packet::ptr reinterpret(Packet * p) = 0;
- };
-
- template <class OtherPacket>
+ template <class PacketType>
struct PkReg_EntryImpl
: public PkReg_Entry
{
- virtual void registerInterpreter(Packet const * p, Packet::iterator b, Packet::iterator e);
- virtual Packet::ptr reinterpret(Packet * p);
+ virtual PacketInterpreterBase::factory_t factory() const;
};
-
template <class KeyType>
- class PacketRegistryImpl : private boost::noncopyable
+ class PacketRegistryImpl
+ : private boost::noncopyable
{
public:
///////////////////////////////////////////////////////////////////////////
typedef KeyType key_t;
- typedef impl::PkReg_Entry Entry;
+ typedef PkReg_Entry Entry;
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@}
///////////////////////////////////////////////////////////////////////////
- template <class OtherPacket>
+ template <class PacketType>
void registerPacket(key_t key);
key_t key(senf::TypeIdValue const & type);
+ boost::optional<key_t> key(senf::TypeIdValue const & type, bool);
- Entry * lookup(key_t key);
+ Entry const & lookup(key_t key);
+ Entry const * lookup(key_t key, bool);
protected:
private:
- template <class OtherPacket>
- static void registerInterpreter(Packet * p, Packet::iterator b, Packet::iterator e);
-
- typedef boost::shared_ptr<Entry> Entry_ptr;
+ typedef boost::intrusive_ptr<Entry> Entry_ptr;
typedef std::map<key_t, Entry_ptr> PacketMap;
typedef std::map<senf::TypeIdValue, key_t> ReversePacketMap;
ReversePacketMap reverseRegistry_;
};
- extern PkReg_EntryImpl<DataPacket> pkreg_dataEntry;
-
}}
///////////////////////////////ih.e////////////////////////////////////////
// Custom includes
#include <string>
#include "PacketRegistry.hh"
-#include "DataPacket.hh"
+#include "PacketType.hh"
#include "ParseInt.hh"
#include <boost/test/auto_unit_test.hpp>
typedef std::string key_t;
};
- class BasePacket
- : public Packet, public PacketRegistryMixin<BaseTag,BasePacket>
- {
- using PacketRegistryMixin<BaseTag,BasePacket>::registerInterpreter;
- public:
- typedef ptr_t<BasePacket>::ptr ptr;
- typedef iterator byte_iterator;
-
- typedef Parse_UInt16<iterator> Parse_Type;
-
- Parse_Type type() const { return Parse_Type(begin()); }
- static bool check(iterator b, iterator e) { return true; }
-
- private:
- template <class Arg>
- BasePacket(Arg const & arg) : Packet(arg) {}
-
- virtual void v_nextInterpreter() const
- { registerInterpreter(type(), begin()+2, end()); }
- virtual void v_finalize() {}
- virtual void v_dump(std::ostream & os) const {}
-
- friend class Packet;
- };
-
- class FooPacket : public Packet
- {
- public:
- typedef ptr_t<FooPacket>::ptr ptr;
- typedef iterator byte_iterator;
-
- static bool check(iterator b, iterator e) { return true; }
-
- private:
- template <class Arg>
- FooPacket(Arg const & arg) : Packet(arg) {}
-
- virtual void v_nextInterpreter() const {}
- virtual void v_finalize() {}
- virtual void v_dump(std::ostream & os) const {}
-
- friend class Packet;
- };
-
- class BarPacket : public Packet
- {
- public:
- typedef ptr_t<BarPacket>::ptr ptr;
- typedef iterator byte_iterator;
-
- static bool check(iterator b, iterator e) { return true; }
-
- private:
- template <class Arg>
- BarPacket(Arg const & arg) : Packet(arg) {}
-
- virtual void v_nextInterpreter() const {}
- virtual void v_finalize() {}
- virtual void v_dump(std::ostream & os) const {}
-
- friend class Packet;
- };
+ struct FooPacketType : public PacketTypeBase {};
+ struct BarPacketType : public PacketTypeBase {};
+ struct OtherPacketType : public PacketTypeBase {};
namespace reg {
- PacketRegistry<StringTag>::RegistrationProxy<FooPacket> registerFoo ("foo");
- PacketRegistry<StringTag>::RegistrationProxy<BarPacket> registerBar ("bar");
+ PacketRegistry<StringTag>::RegistrationProxy<FooPacketType> registerFoo ("foo");
+ PacketRegistry<StringTag>::RegistrationProxy<BarPacketType> registerBar ("bar");
}
}
BOOST_AUTO_UNIT_TEST(packetRegistry_test)
{
- unsigned char data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
-
- {
- BasePacket::ptr p (Packet::create<BasePacket>(data, data+sizeof(data)));
- BOOST_CHECK( p->next()->is<DataPacket>() );
- }
-
- PacketRegistry<BaseTag>::registerPacket<FooPacket>(1u);
- PacketRegistry<BaseTag>::registerPacket<BarPacket>(2u);
-
- BOOST_CHECK_EQUAL( PacketRegistry<BaseTag>::key<FooPacket>(), 1u );
- BOOST_CHECK_EQUAL( PacketRegistry<BaseTag>::key<BarPacket>(), 2u );
- BOOST_CHECK_THROW( PacketRegistry<BaseTag>::key<DataPacket>(), PacketTypeNotRegistered );
+ PacketRegistry<BaseTag>::registerPacket<FooPacketType>(1u);
+ PacketRegistry<BaseTag>::registerPacket<BarPacketType>(2u);
- {
- BasePacket::ptr p (Packet::create<BasePacket>(data, data+sizeof(data)));
- BOOST_CHECK( p->next()->is<FooPacket>() );
- }
-
- data[1] = 0x02;
-
- {
- BasePacket::ptr p (Packet::create<BasePacket>(data, data+sizeof(data)));
- BOOST_CHECK( p->next()->is<BarPacket>() );
- }
-
- data[0] = 0x01;
-
- {
- BasePacket::ptr p (Packet::create<BasePacket>(data, data+sizeof(data)));
- BOOST_CHECK( p->next()->is<DataPacket>() );
- }
+ BOOST_CHECK_EQUAL( PacketRegistry<BaseTag>::key<FooPacketType>(), 1u );
+ BOOST_CHECK_EQUAL( PacketRegistry<BaseTag>::key<BarPacketType>(), 2u );
+ BOOST_CHECK_THROW( PacketRegistry<BaseTag>::key<OtherPacketType>(),
+ PacketTypeNotRegisteredException );
- BOOST_CHECK_EQUAL( PacketRegistry<StringTag>::key<FooPacket>(), "foo" );
- BOOST_CHECK( PacketRegistry<StringTag>::create("foo",data,data+sizeof(data))
- ->is<FooPacket>() );
+ BOOST_CHECK_EQUAL( PacketRegistry<StringTag>::key<FooPacketType>(), "foo" );
+ BOOST_CHECK( ! PacketRegistry<StringTag>::lookup("blub", senf::nothrow) );
+ BOOST_CHECK( PacketRegistry<BaseTag>::lookup(1u, senf::nothrow) );
}
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketType inline non-template implementation */
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketTypeBase
+
+prefix_ senf::PacketTypeBase::optional_range senf::PacketTypeBase::no_range()
+{
+ return PacketInterpreterBase::no_range();
+}
+
+prefix_ senf::PacketTypeBase::factory_t senf::PacketTypeBase::no_factory()
+{
+ return PacketInterpreterBase::no_factory();
+}
+
+prefix_ senf::PacketTypeBase::size_type senf::PacketTypeBase::initSize()
+{
+ return 0;
+}
+
+prefix_ senf::PacketTypeBase::size_type senf::PacketTypeBase::initHeadSize()
+{
+ return size_type(-1);
+}
+
+prefix_ void senf::PacketTypeBase::init(packet)
+{}
+
+prefix_ senf::PacketTypeBase::optional_range senf::PacketTypeBase::nextPacketRange(packet p)
+{
+ return PacketInterpreterBase::no_range();
+}
+
+prefix_ senf::PacketTypeBase::factory_t senf::PacketTypeBase::nextPacketType(packet p)
+{
+ return PacketInterpreterBase::no_factory();
+}
+
+prefix_ void senf::PacketTypeBase::finalize(packet)
+{}
+
+prefix_ void senf::PacketTypeBase::dump(packet p, std::ostream & os)
+{}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketType inline template implementation */
+
+//#include "PacketType.ih"
+
+// Custom includes
+#include <boost/utility.hpp>
+#include "PacketRegistry.hh"
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketTypeBase
+
+template <class PacketType>
+prefix_ senf::PacketTypeBase::factory_t senf::PacketTypeBase::factory()
+{
+ return PacketInterpreter<PacketType>::factory();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketTypeMixin<Self,Registry>
+
+template <class Self, class Registry>
+prefix_ senf::PacketInterpreterBase::optional_range
+senf::PacketTypeMixin<Self,Registry>::nextPacketRange(Packet p)
+{
+ // Call the member defined in the specialization below
+ return PacketTypeMixin<Self>::nextPacketRange(p);
+}
+
+template <class Self, class Registry>
+prefix_ senf::PacketInterpreterBase::factory_t
+senf::PacketTypeMixin<Self,Registry>::nextPacketType(Packet p)
+{
+ if (p.data().size() < Self::initSize())
+ return Self::no_factory();
+ PkReg_Entry const * e (PacketRegistry<Registry>::lookup(
+ Self::nextPacketKey(p.as< ConcretePacket<Self> >()), nothrow));
+ return e ? e->factory() : PacketTypeBase::no_factory();
+}
+
+template <class Self, class Registry>
+prefix_ senf::PacketInterpreterBase::size_type senf::PacketTypeMixin<Self,Registry>::initSize()
+{
+ return senf::init_bytes< typename Self::parser >::value;
+}
+
+template <class Self, class Registry>
+prefix_ void senf::PacketTypeMixin<Self,Registry>::init(Packet p)
+{
+ p.as< ConcretePacket<Self> >()->init();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketTypeMixin<Self,void>
+
+template <class Self>
+prefix_ senf::PacketInterpreterBase::optional_range
+senf::PacketTypeMixin<Self,void>::nextPacketRange(Packet p)
+{
+ if (p.data().size() < Self::initSize())
+ return PacketTypeBase::no_range();
+ typename Self::size_type sz (Self::initHeadSize());
+ ///\idea This if condition could be replaced with a compile time switch by checking, wether
+ /// (the function address) Self::initHeadSize is different from PacketTypeBase::initHeadSize
+ if (sz == PacketTypeBase::size_type(-1))
+ return PacketTypeBase::range(boost::next(p.data().begin(),Self::initSize()),
+ p.data().end());
+ else
+ return PacketTypeBase::range(boost::next(p.data().begin(),sz),
+ boost::prior(p.data().end(),Self::initSize()-sz));
+}
+
+template <class Self>
+prefix_ senf::PacketInterpreterBase::size_type senf::PacketTypeMixin<Self,void>::initSize()
+{
+ return senf::init_bytes< typename Self::parser >::value;
+}
+
+template <class Self>
+prefix_ void senf::PacketTypeMixin<Self,void>::init(Packet p)
+{
+ p.as< ConcretePacket<Self> >()->init();
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketType public header */
+
+#ifndef HH_PacketType_
+#define HH_PacketType_ 1
+
+// Custom includes
+#include <iostream>
+#include "PacketTypes.hh"
+#include "PacketData.hh"
+#include "PacketParser.hh"
+#include "Packet.hh"
+
+//#include "PacketType.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ /** \brief Helper baseclass implementing the PacketType interface
+
+ This helper class maybe used when building a new PacketType. It provides a complete default
+ implementations of this interface. To define a new PacketType, derive from this class and
+ implement the members you want to change.
+
+ \code
+ struct SomePacketType : public senf::PacketTypeBase
+ {
+ typedef senf::ConcretePacket<SomePacketType> packet;
+ typedef SomePacketParser parser;
+
+ static size_type initSize()
+ {
+ // This value can in most cases be taken from the parser
+ return senf::init_size<parser>::value;
+ }
+
+ static size_type initHeadSize()
+ {
+ // optional member. This is only needed, if the packet has header and trailer.
+ return constant_initial_size_of_header
+ }
+
+ static void init(packet p)
+ {
+ // Initialize a new packet by e.g. setting some fields. Should call
+ // the packet parsers init() member
+ p->init();
+ p->some_field() = 1;
+ }
+
+ static optional_range nextPacketRange(packet p)
+ {
+ if (have_next_packet)
+ // return iterator range delimiting the packet, e.g.:
+ return range(p.data()+begin_offset, p.data()+end_offset);
+ else
+ return no_range();
+ }
+
+ static factory_t nextPacketType(packet p)
+ {
+ if (have_next_packet && know_next_packet_type)
+ // \a NextPacket is the \c ConcretePacket instantiation of the next packet
+ return NextPacket::factory();
+ else
+ return no_factory();
+ }
+
+ static void finalize(packet p)
+ {
+ // optionally complete the packet by generating autogenerated information
+ // (like checksums)
+ }
+
+ static void dump(packet p, std::ostream & os)
+ {
+ // Write out a readable representation of the packet for debug purposes
+ }
+ }
+ \endcode
+
+ You may leave out any one of the members (you should however always define the \c
+ interpreter typedef member)
+ */
+ struct PacketTypeBase
+ {
+ typedef Packet packet;
+
+ typedef senf::detail::packet::iterator iterator;
+ typedef senf::detail::packet::const_iterator const_iterator;
+ typedef senf::detail::packet::size_type size_type;
+ typedef senf::detail::packet::difference_type difference_type;
+ typedef senf::detail::packet::byte byte;
+
+ typedef PacketInterpreterBase::range range;
+ typedef PacketInterpreterBase::optional_range optional_range;
+ typedef PacketInterpreterBase::factory_t factory_t;
+
+ static optional_range no_range();
+ static factory_t no_factory();
+ template <class PacketType> static factory_t factory();
+
+ typedef VoidPacketParser parser;
+ ///< Parser to parser packet fields
+ /**< This typedef has to be set to the parser of the packet
+
+ The default is a VoidPacketParser which does not parser
+ any field. */
+
+ static size_type initSize();
+ ///< Get size of new (empty) packet
+ /**< The default implementation returns 0.
+ \returns size that needs to be allocated to a newly
+ constructed packet */
+
+ static size_type initHeadSize();
+ ///< Get size of new (empty) packet header
+ /**< This function gives the index within a newly created,
+ empty packet where a subpacket is to be placed.
+
+ The default implementation returns initSize().
+
+ \implementation Ok, it does not really return
+ initSize(), it returns size_type(-1) which is
+ interpreted to mean initSize(). It can't return
+ initSize since initSize() is not (and can't be
+ since it is static) virtual. */
+
+ static void init(packet p);
+ ///< Initialize new packet
+ /**< This member is called to initialize a just created new
+ packet. The new packet will have a size of at least
+ initSize() but the size may well be larger. It is also
+ possible for the packet to already have further
+ subpackets.
+
+ The default implementation does nothing. */
+
+
+
+ static optional_range nextPacketRange(packet p);
+ ///< Get next packet placement
+ /**< nextPacketRange returns the iterator range where the
+ next packet (header) is placed within the current
+ packet.
+
+ The default implementation always returns
+ <tt>no_range()</tt>.
+
+ \returns nextPacketRange must return
+ \li <tt>\ref interpreter::range(b,e)</tt> (where \a b
+ and \a e are the iterators delimiting the next
+ packet range) if the packet allows a next
+ header. The returned range is allowed to be empty.
+ \li <tt>\ref interpreter::no_range()</tt> (a
+ default constructed \c no_range instance) if
+ no next header is allowed */
+
+ static factory_t nextPacketType(packet p);
+ ///< Get type of next packet
+ /**< nextPacketType retrieves the type of the next packet
+ returning a factory to create that packet.
+
+ The default implementation always returns
+ <tt>no_factory()</tt>.
+
+ \returns factory to create next packet
+ \li <tt>interpreter::factory<OtherPacketType>()</tt> if
+ the type of the packet can be determined
+ \li <tt>interpreter::no_factory()</tt> if the type of
+ the packet cannot be determined or no next packet
+ is supported */
+
+ static void finalize(packet p);
+ ///< Finalize packet
+ /**< finalize() will be called to complete a packet after it
+ has been modified. This function must calculate any
+ checksums, set size fields from the interpreter chain
+ etc.
+
+ The default implementation does nothing. */
+
+ static void dump(packet p, std::ostream & os);
+ ///< Dump packet data in readable form
+ /**< The dump() function writes out a complete
+ representation of the packet. This is used formost for
+ debugging purposes.
+
+ The default implementation does nothing. */
+ };
+
+
+ /** \brief Mixin to provide standard implementations for nextPacketRange and nextPacketType
+
+ This mixin class simplifies the definition of simple packets with fixed-size headers and/or
+ trailers. For this type of Packet, this mixin provides the nextPacketRange() and
+ nextPacketType() members:
+ \code
+ struct SimplePacketType
+ : public senf::PacketTypeBase
+ pyblic senf:PacketTypeMixin<SimplePacketType, SomeRegistryTag>
+ {
+ static interpreter::size_type initSize()
+ {
+ // This member is optional. If it is not defined, 'senf::init_size<parser>::value'
+ // will be returned.
+
+ // The value returned is the length of the header if initHeadSize() is not defined.
+ // If initHeadSize is defined, this value is the combined size of the header
+ // and trailer while initHeadSize() will return the size of the header only.
+ return packet_size;
+ }
+
+ static interpreter::size_type initHeadSize()
+ {
+ // This member is optional. It returns the header size if the packet has a
+ // trailer.
+ return header_size;
+ }
+
+ static registry_key_t nextPacketKey(packet p)
+ {
+ // Return the key in the registry under which the next packet
+ // header is to be found. This member must be given if a Registry argument is
+ // passed to the PacketTypeMixin template.
+ return i.fields().typeField();
+ }
+ };
+ \endcode
+ */
+ template <class Self, class Registry=void>
+ class PacketTypeMixin
+ {
+ public:
+ typedef typename Registry::key_t registry_key_t;
+
+ static PacketInterpreterBase::optional_range nextPacketRange (Packet p);
+ static PacketInterpreterBase::factory_t nextPacketType (Packet p);
+ static PacketInterpreterBase::size_type initSize ();
+ static void init (Packet p);
+ };
+
+ template <class Self>
+ class PacketTypeMixin<Self,void>
+ {
+ public:
+ static PacketInterpreterBase::optional_range nextPacketRange (Packet p);
+ static PacketInterpreterBase::size_type initSize ();
+ static void init (Packet p);
+ };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "PacketType.cci"
+//#include "PacketType.ct"
+#include "PacketType.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief PacketTypes public header */
+
+#ifndef HH_PacketTypes_
+#define HH_PacketTypes_ 1
+
+// Custom includes
+#include <vector>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/intrusive/ilist.hpp>
+#include <boost/intrusive/ilist_hook.hpp>
+
+//#include "PacketTypes.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ class PacketData;
+ class PacketInterpreterBase;
+
+namespace detail {
+
+ class PacketImpl;
+
+namespace packet {
+
+ template <class T>
+ struct smart_pointer {
+ typedef boost::intrusive_ptr<T> ptr_t;
+ };
+
+ struct interpreter_list_tag;
+ typedef boost::intrusive::ilist_base_hook<interpreter_list_tag> interpreter_list_base;
+ typedef interpreter_list_base::value_traits<PacketInterpreterBase> interpreter_list_type;
+
+ typedef boost::intrusive::ilist<interpreter_list_type,false> interpreter_list;
+
+ typedef boost::uint8_t byte;
+ typedef std::vector<byte> raw_container;
+ typedef raw_container::size_type size_type;
+ typedef raw_container::difference_type difference_type;
+
+ typedef raw_container::iterator iterator;
+ typedef raw_container::const_iterator const_iterator;
+ typedef long refcount_t; // This is long since boost uses long for refcounts .. hmm ..
+
+namespace test {
+
+ class TestDriver;
+
+}}}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "PacketTypes.cci"
+//#include "PacketTypes.ct"
+//#include "PacketTypes.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline template functions
+/** \file
+ \brief ParseArray non-inline template implementation */
-//#include "GenericPacket.ih"
+//#include "ParseArray.ih"
// Custom includes
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::v_nextInterpreter()
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_Array<elements,ElementParser>
+
+template <unsigned elements, class ElementParser>
+prefix_ void senf::Parse_Array<elements,ElementParser>::init()
const
{
- this->registerInterpreter<DataPacket>(this->end_header(), this->begin_trailer());
+ iterator i (begin());
+ iterator const e (end());
+ for (; i!=e; ++i)
+ (*i).init();
}
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::v_finalize()
-{}
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::v_dump(std::ostream & os)
- const
-{
- /// \todo implement v_dump()
-}
///////////////////////////////ct.e////////////////////////////////////////
#undef prefix_
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ senf::Parse_Array<elements,Parser,Iterator,IPacket>::Parse_Array()
-{}
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_Array<elements,ElementParser>
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::Parse_Array(Iterator const & i)
- : ParserBase<Iterator,IPacket>(i)
+template <unsigned elements, class ElementParser>
+prefix_ senf::Parse_Array<elements,ElementParser>::Parse_Array(data_iterator i, state_type s)
+ : PacketParserBase(i,s,fixed_bytes)
{}
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ unsigned senf::Parse_Array<elements,Parser,Iterator,IPacket>::bytes()
-{
- return elements*Parser::bytes();
-}
-
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ bool
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::check(Iterator const & e)
- const
-{
- return e-this->i() >= bytes();
-}
-
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ void senf::Parse_Array<elements,Parser,Iterator,IPacket>::init()
- const
-{
- iterator e=end();
- for (iterator i=begin(); i!=e; ++i) i->init();
-}
-
-///////////////////////////////////////////////////////////////////////////
+// Container interface
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Array<elements,Parser,Iterator,IPacket>::size_type
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::size()
+template <unsigned elements, class ElementParser>
+prefix_ typename senf::Parse_Array<elements,ElementParser>::size_type
+senf::Parse_Array<elements,ElementParser>::size()
{
return elements;
}
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Array<elements,Parser,Iterator,IPacket>::iterator
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::begin()
- const
-{
- return iterator(this->i());
-}
-
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Array<elements,Parser,Iterator,IPacket>::iterator
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::end()
- const
-{
- return iterator(this->i()+bytes());
-}
-
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Array<elements,Parser,Iterator,IPacket>::range_type
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::range()
+template <unsigned elements, class ElementParser>
+prefix_ typename senf::Parse_Array<elements,ElementParser>::iterator
+senf::Parse_Array<elements,ElementParser>::begin()
const
{
- return std::make_pair(begin(),end());
+ return iterator(i(),state());
}
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Array<elements,Parser,Iterator,IPacket>::iterator
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::value()
+template <unsigned elements, class ElementParser>
+prefix_ typename senf::Parse_Array<elements,ElementParser>::iterator
+senf::Parse_Array<elements,ElementParser>::end()
const
{
- return begin();
+ return iterator(boost::next(i(),fixed_bytes),state());
}
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Array<elements,Parser,Iterator,IPacket>::value_type
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::operator[](difference_type i)
+template <unsigned elements, class ElementParser>
+prefix_ typename senf::Parse_Array<elements,ElementParser>::value_type
+senf::Parse_Array<elements,ElementParser>::operator[](difference_type i)
const
{
+ BOOST_ASSERT( i>=0 && i < difference_type(elements) );
return begin()[i];
}
-template <unsigned elements, class Parser, class Iterator, class IPacket>
-template <class InputIterator>
-prefix_ senf::Parse_Array<elements,Parser,Iterator,IPacket> const &
-senf::Parse_Array<elements,Parser,Iterator,IPacket>::operator=(InputIterator const & i)
-{
- copy_n(i,size(),begin());
-}
-
///////////////////////////////////////////////////////////////////////////
+// senf::detail::Parse_Array_iterator<ElementParser>
+
+template <class ElementParser>
+prefix_ senf::detail::Parse_Array_iterator<ElementParser>::Parse_Array_iterator()
+ : i_()
+{}
+
+template <class ElementParser>
+prefix_ senf::detail::Parse_Array_iterator<ElementParser>::
+Parse_Array_iterator(PacketParserBase::data_iterator const & i, PacketParserBase::state_type s)
+ : i_(i), s_(s)
+{}
-template <class Parser, class Iterator>
-prefix_ Iterator senf::impl::Parse_Array_iterator<Parser,Iterator>::raw()
+template <class ElementParser>
+prefix_ ElementParser
+senf::detail::Parse_Array_iterator<ElementParser>::operator[](int i)
const
{
- return i_;
+ return (*this+i).dereference();
}
-template <class Parser, class Iterator>
-prefix_ Parser senf::impl::Parse_Array_iterator<Parser,Iterator>::operator[](int i)
+template <class ElementParser>
+prefix_ senf::PacketParserBase::data_iterator
+senf::detail::Parse_Array_iterator<ElementParser>::raw()
const
{
- return (*this+i).dereference();
+ return i_;
}
-template <class Parser, class Iterator>
-prefix_ senf::impl::Parse_Array_iterator<Parser,Iterator>::Parse_Array_iterator()
- : i_()
-{}
+// iterator_facade interface
-template <class Parser, class Iterator>
-prefix_ senf::impl::Parse_Array_iterator<Parser,Iterator>::
-Parse_Array_iterator(Iterator const & i)
- : i_(i)
-{}
-
-template <class Parser, class Iterator>
-prefix_ Parser
-senf::impl::Parse_Array_iterator<Parser,Iterator>::dereference()
+template <class ElementParser>
+prefix_ ElementParser
+senf::detail::Parse_Array_iterator<ElementParser>::dereference()
const
{
- return Parser(i_);
+ return ElementParser(i_,s_);
}
-template <class Parser, class Iterator>
-prefix_ bool senf::impl::Parse_Array_iterator<Parser,Iterator>::
+template <class ElementParser>
+prefix_ bool
+senf::detail::Parse_Array_iterator<ElementParser>::
equal(Parse_Array_iterator const & other)
const
{
return i_==other.i_;
}
-template <class Parser, class Iterator>
-prefix_ int senf::impl::Parse_Array_iterator<Parser,Iterator>::
+template <class ElementParser>
+prefix_ int senf::detail::Parse_Array_iterator<ElementParser>::
distance_to(Parse_Array_iterator const & other)
const
{
- return (other.i_-i_)/Parser::bytes();
+ return (other.i_-i_)/ElementParser::fixed_bytes;
}
-template <class Parser, class Iterator>
-prefix_ void senf::impl::Parse_Array_iterator<Parser,Iterator>::increment()
+template <class ElementParser>
+prefix_ void senf::detail::Parse_Array_iterator<ElementParser>::increment()
{
- i_ += Parser::bytes();
+ i_ += ElementParser::fixed_bytes;
}
-template <class Parser, class Iterator>
-prefix_ void senf::impl::Parse_Array_iterator<Parser,Iterator>::decrement()
+template <class ElementParser>
+prefix_ void senf::detail::Parse_Array_iterator<ElementParser>::decrement()
{
- i_ -= Parser::bytes();
+ i_ -= ElementParser::fixed_bytes;
}
-template <class Parser, class Iterator>
-prefix_ void
-senf::impl::Parse_Array_iterator<Parser,Iterator>::advance(int n)
+template <class ElementParser>
+prefix_ void senf::detail::Parse_Array_iterator<ElementParser>::advance(int n)
{
- i_ += n*Parser::bytes();
+ i_ += n*ElementParser::fixed_bytes;
}
#undef copy_n
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
#define HH_ParseArray_ 1
// Custom includes
-#include <utility> // for std::pair
-#include "ParserBase.hh"
+#include "PacketParser.hh"
//#include "ParseArray.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
-
- namespace impl { template <class,class> class Parse_Array_iterator; }
+ namespace detail { template <class> class Parse_Array_iterator; }
/* Parse_Array has the external interface of a container class
*/
- template <unsigned elements, class Parser, class Iterator=nil, class IPacket=nil>
- struct Parse_Array : public ParserBase<Iterator,IPacket>
+ template <unsigned elements, class ElementParser>
+ struct Parse_Array : public PacketParserBase
{
- ///////////////////////////////////////////////////////////////////////////
- // Parser interface
+ Parse_Array(data_iterator i, state_type s);
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Array<elements,Parser,I,P> parser; };
- typedef Iterator byte_iterator;
+ static size_type const fixed_bytes = elements*ElementParser::fixed_bytes;
- Parse_Array();
- explicit Parse_Array(Iterator const & i);
-
- static unsigned bytes();
- bool check(Iterator const & e) const;
void init() const;
///////////////////////////////////////////////////////////////////////////
// Container interface
- typedef typename Parser::template rebind<Iterator>::parser value_type;
- typedef impl::Parse_Array_iterator<value_type,Iterator> iterator;
- typedef unsigned size_type;
- typedef int difference_type;
- typedef std::pair<iterator,iterator> range_type;
+ typedef ElementParser value_type;
+ typedef detail::Parse_Array_iterator<value_type> iterator;
+ typedef iterator const_iterator;
static size_type size();
iterator begin() const;
iterator end() const;
- range_type range() const;
- iterator value() const;
value_type operator[](difference_type i) const;
-
- template <class InputIterator>
- Parse_Array const & operator= (InputIterator const & i);
};
}
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
///////////////////////////////ih.p////////////////////////////////////////
-template <class Parser, class Iterator>
-class senf::impl::Parse_Array_iterator
- : public boost::iterator_facade< Parse_Array_iterator<Parser,Iterator>,
- Parser,
+template <class ElementParser>
+class senf::detail::Parse_Array_iterator
+ : public boost::iterator_facade< Parse_Array_iterator<ElementParser>,
+ ElementParser,
boost::random_access_traversal_tag,
- Parser >
+ ElementParser >
{
public:
Parse_Array_iterator();
- explicit Parse_Array_iterator(Iterator const & i);
+ Parse_Array_iterator(PacketParserBase::data_iterator const & i,
+ PacketParserBase::state_type s);
// Needed to elide the []-proxy of iterator_facade
- Parser operator[](int i) const;
+ ElementParser operator[](int i) const;
- Iterator raw() const;
+ PacketParserBase::data_iterator raw() const;
protected:
private:
friend class boost::iterator_core_access;
+
+ // iterator_facade interface
- Parser dereference() const;
+ ElementParser dereference() const;
bool equal(Parse_Array_iterator const & other) const;
int distance_to(Parse_Array_iterator const & other) const;
void increment();
void decrement();
void advance(int n);
- Iterator i_;
+ PacketParserBase::data_iterator i_;
+ PacketParserBase::state_type s_;
};
///////////////////////////////ih.e////////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
//#include "ParseArray.test.ih"
// Custom includes
+#include "PacketInterpreter.hh"
#include "ParseArray.hh"
#include "ParseInt.hh"
+#include "PacketType.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase
+ {};
+
+ struct SomePacketParser : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(SomePacketParser);
+
+ typedef senf::Parse_Array<2,senf::Parse_UInt24> Parse_Array2;
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((Field)( array, Parse_Array2 ))
+ ((Field)( index, senf::Parse_UInt16 )) );
+ };
+
+ struct SomeOtherParser : public senf::PacketParserBase
+ {
+ SENF_PACKET_PARSER_INIT(SomeOtherParser);
+
+ typedef senf::Parse_Array<1,SomePacketParser> Parse_Array1;
+
+ SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
+ ((Field)( fields, Parse_Array1 )) );
+ };
+}
BOOST_AUTO_UNIT_TEST(parseArray_test)
{
- unsigned char data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
- typedef unsigned char * iterator;
- typedef Parse_Array<6,Parse_UInt8<>,iterator> Parse_UInt8Array6;
- Parse_UInt8Array6 v (data);
- BOOST_CHECK_EQUAL( v[0], 0x00 );
- BOOST_CHECK_EQUAL( v[5], 0x05 );
- BOOST_CHECK_EQUAL( *v.begin(), 0x00 );
- Parse_UInt8Array6::iterator i1 (v.begin());
- Parse_UInt8Array6::iterator i2 (v.begin());
- ++i1;
- BOOST_CHECK_EQUAL( *i1, 0x01 );
- BOOST_CHECK_EQUAL( i1[-1], 0x00 );
- BOOST_CHECK_EQUAL( i1-i2, 1 );
- BOOST_CHECK_EQUAL( i2-i1, -1 );
- --i1;
- BOOST_CHECK( i1==i2 );
+ senf::PacketParserBase::byte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+ senf::PacketInterpreterBase::ptr p (senf::PacketInterpreter<VoidPacket>::create(data));
+
+ {
+ typedef senf::Parse_Array<6,senf::Parse_UInt8> Parse_UInt8Array6;
+ Parse_UInt8Array6 v (p->data().begin(),&p->data());
+
+ BOOST_CHECK_EQUAL( v[0], 0x00 );
+ BOOST_CHECK_EQUAL( v[5], 0x05 );
+ BOOST_CHECK_EQUAL( *v.begin(), 0x00 );
+ BOOST_CHECK_EQUAL( std::distance(v.begin(),v.end()),
+ Parse_UInt8Array6::difference_type(v.size()) );
+ BOOST_CHECK_EQUAL( v.size(), 6u );
+ Parse_UInt8Array6::iterator i1 (v.begin());
+ Parse_UInt8Array6::iterator i2 (v.begin());
+ ++i1;
+ BOOST_CHECK_EQUAL( *i1, 0x01 );
+ BOOST_CHECK_EQUAL( i1[-1], 0x00 );
+ BOOST_CHECK_EQUAL( i1-i2, 1 );
+ BOOST_CHECK_EQUAL( i2-i1, -1 );
+ --i1;
+ BOOST_CHECK( i1==i2 );
+ }
+
+ {
+ SomeOtherParser v (p->data().begin(),&p->data());
+
+ BOOST_CHECK_THROW( v.fields(), senf::TruncatedPacketException );
+ }
}
///////////////////////////////cc.e////////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
// Custom includes
#include <iostream>
-#include "ParserBase.hh"
#include <boost/cstdint.hpp>
#include <boost/static_assert.hpp>
#include <boost/integer/integer_mask.hpp>
+#include "PacketParser.hh"
//#include "ParseInt.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
-
- template <class Iterator=nil, class IPacket=nil>
struct Parse_Int8
- : public impl::ParseIntOps<Parse_Int8<Iterator,IPacket>,boost::int8_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_Int8,boost::int8_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Int8<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 1; }
-
- Parse_Int8() {}
- explicit Parse_Int8(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_Int8(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::int8_t value_type;
+ static size_type const fixed_bytes = 1;
- value_type value() const { return this->i()[0]; }
- void value(value_type v) { this->i()[0] = v; }
+ value_type value() const { return i()[0]; }
+ void value(value_type v) { i()[0] = v; }
Parse_Int8 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_Int8<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_Int8 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_UInt8
- : public impl::ParseIntOps<Parse_UInt8<Iterator,IPacket>,boost::uint8_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_UInt8,boost::uint8_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_UInt8<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 1; }
-
- Parse_UInt8() {}
- explicit Parse_UInt8(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_UInt8(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::uint8_t value_type;
+ static size_type const fixed_bytes = 1;
- value_type value() const { return this->i()[0]; }
- void value(value_type v) { this->i()[0] = v; }
+ value_type value() const { return i()[0]; }
+ void value(value_type v) { i()[0] = v; }
Parse_UInt8 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_UInt8<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_UInt8 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_Int16
- : public impl::ParseIntOps<Parse_Int16<Iterator,IPacket>,boost::int16_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_Int16,boost::int16_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Int16<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 2; }
-
- Parse_Int16() {}
- explicit Parse_Int16(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_Int16(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::int16_t value_type;
+ static size_type const fixed_bytes = 2;
- value_type value() const { return impl::parse_uint16(this->i()); }
- void value(value_type v) { impl::write_uint16(this->i(),v); }
+ value_type value() const { return detail::packet::parse_uint16(i()); }
+ void value(value_type v) { detail::packet::write_uint16(i(),v); }
Parse_Int16 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_Int16<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_Int16 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_UInt16
- : public impl::ParseIntOps<Parse_UInt16<Iterator,IPacket>,boost::uint16_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_UInt16,boost::uint16_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_UInt16<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 2; }
-
- Parse_UInt16() {}
- explicit Parse_UInt16(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_UInt16(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::uint16_t value_type;
+ static size_type const fixed_bytes = 2;
- value_type value() const { return impl::parse_uint16(this->i()); }
- void value(value_type v) { impl::write_uint16(this->i(),v); }
+ value_type value() const { return detail::packet::parse_uint16(i()); }
+ void value(value_type v) { detail::packet::write_uint16(i(),v); }
Parse_UInt16 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_UInt16<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_UInt16 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_Int24
- : public impl::ParseIntOps<Parse_Int24<Iterator,IPacket>,boost::int32_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_Int24,boost::int32_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Int24<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 3; }
-
- Parse_Int24() {}
- explicit Parse_Int24(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_Int24(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::int32_t value_type;
+ static size_type const fixed_bytes = 3;
value_type value() const {
- value_type v (impl::parse_uint24(this->i())); return v&0x800000 ? v|0xff000000 : v; }
- void value(value_type v) { impl::write_uint24(this->i(),v); }
+ value_type v (detail::packet::parse_uint24(i())); return v&0x800000 ? v|0xff000000 : v; }
+ void value(value_type v) { detail::packet::write_uint24(i(),v); }
Parse_Int24 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_Int24<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_Int24 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_UInt24
- : public impl::ParseIntOps<Parse_UInt24<Iterator,IPacket>,boost::uint32_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_UInt24,boost::uint32_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_UInt24<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 3; }
-
- Parse_UInt24() {}
- explicit Parse_UInt24(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_UInt24(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::uint32_t value_type;
+ static size_type const fixed_bytes = 3;
- value_type value() const { return impl::parse_uint24(this->i()); }
- void value(value_type v) { impl::write_uint24(this->i(),v); }
+ value_type value() const { return detail::packet::parse_uint24(i()); }
+ void value(value_type v) { detail::packet::write_uint24(i(),v); }
Parse_UInt24 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_UInt24<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_UInt24 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_Int32
- : public impl::ParseIntOps<Parse_Int32<Iterator,IPacket>,boost::int32_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_Int32,boost::int32_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Int32<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 4; }
-
- Parse_Int32() {}
- explicit Parse_Int32(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_Int32(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::int32_t value_type;
+ static size_type const fixed_bytes = 4;
- value_type value() const { return impl::parse_uint32(this->i()); }
- void value(value_type v) { impl::write_uint32(this->i(),v); }
+ value_type value() const { return detail::packet::parse_uint32(i()); }
+ void value(value_type v) { detail::packet::write_uint32(i(),v); }
Parse_Int32 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_Int32<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_Int32 const & i)
{ os << i.value(); return os; }
- template <class Iterator=nil, class IPacket=nil>
struct Parse_UInt32
- : public impl::ParseIntOps<Parse_UInt32<Iterator,IPacket>,boost::uint32_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_UInt32,boost::uint32_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_UInt32<I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 4; }
-
- Parse_UInt32() {}
- explicit Parse_UInt32(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_UInt32(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::uint32_t value_type;
+ static size_type const fixed_bytes = 4;
- value_type value() const { return impl::parse_uint32(this->i()); }
- void value(value_type v) { impl::write_uint32(this->i(),v); }
+ value_type value() const { return detail::packet::parse_uint32(i()); }
+ void value(value_type v) { detail::packet::write_uint32(i(),v); }
Parse_UInt32 const & operator= (value_type other) { value(other); return *this; }
};
- template <class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_UInt32<Iterator,IPacket> const & i)
+ inline std::ostream & operator<<(std::ostream & os, Parse_UInt32 const & i)
{ os << i.value(); return os; }
- template <unsigned start, unsigned end, class Iterator=nil, class IPacket=nil>
+ template <unsigned Start, unsigned End>
struct Parse_IntField
- : public impl::ParseIntOps<Parse_IntField<start,end,Iterator,IPacket>,boost::int32_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_IntField<Start,End>,boost::int32_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_IntField<start,end,I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return (end-1)/8+1; }
-
- Parse_IntField() {}
- explicit Parse_IntField(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_IntField(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::int32_t value_type;
+ static size_type const fixed_bytes = (End-1)/8+1;
value_type value() const {
- value_type v (impl::parse_bitfield<Iterator,start,end>::parse(this->i()));
- return v&boost::high_bit_mask_t<end-start-1>::high_bit ?
- v | ~boost::low_bits_mask_t<end-start>::sig_bits : v;
+ value_type v (detail::packet::parse_bitfield<Start,End>::parse(i()));
+ return v&boost::high_bit_mask_t<End-Start-1>::high_bit ?
+ v | ~boost::low_bits_mask_t<End-Start>::sig_bits : v;
}
- void value(value_type v) { impl::parse_bitfield<Iterator,start,end>::write(this->i(),v); }
+ void value(value_type v) { detail::packet::parse_bitfield<Start,End>::write(i(),v); }
Parse_IntField const & operator= (value_type other) { value(other); return *this; }
private:
- BOOST_STATIC_ASSERT( start<end );
- BOOST_STATIC_ASSERT( end-start<=32 );
+ BOOST_STATIC_ASSERT( Start<End );
+ BOOST_STATIC_ASSERT( End-Start<=32 );
};
- template <unsigned start, unsigned end, class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_IntField<start,end,Iterator,IPacket> const & i)
+ template <unsigned Start, unsigned End>
+ inline std::ostream & operator<<(std::ostream & os, Parse_IntField<Start,End> const & i)
{ os << i.value(); return os; }
- template <unsigned start, unsigned end, class Iterator=nil, class IPacket=nil>
+ template <unsigned Start, unsigned End>
struct Parse_UIntField
- : public impl::ParseIntOps<Parse_UIntField<start,end,Iterator,IPacket>,boost::uint32_t>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_UIntField<Start,End>,boost::uint32_t>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_UIntField<start,end,I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return (end-1)/8+1; }
-
- Parse_UIntField() {}
- explicit Parse_UIntField(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_UIntField(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef boost::uint32_t value_type;
+ static size_type const fixed_bytes = (End-1)/8+1;
- value_type value() const { return impl::parse_bitfield<Iterator,start,end>::parse(this->i()); }
- void value(value_type v) { impl::parse_bitfield<Iterator,start,end>::write(this->i(),v); }
+ value_type value() const { return detail::packet::parse_bitfield<Start,End>::parse(i()); }
+ void value(value_type v) { detail::packet::parse_bitfield<Start,End>::write(i(),v); }
Parse_UIntField const & operator= (value_type other) { value(other); return *this; }
private:
- BOOST_STATIC_ASSERT( start<end );
- BOOST_STATIC_ASSERT( end-start<=32 );
+ BOOST_STATIC_ASSERT( Start<End );
+ BOOST_STATIC_ASSERT( End-Start<=32 );
};
- template <unsigned start, unsigned end, class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_UIntField<start,end,Iterator,IPacket> const & i)
+ template <unsigned Start, unsigned End>
+ inline std::ostream & operator<<(std::ostream & os, Parse_UIntField<Start,End> const & i)
{ os << i.value(); return os; }
- template <unsigned bit, class Iterator=nil, class IPacket=nil>
+ template <unsigned bit>
struct Parse_Flag
- : public impl::ParseIntOps<Parse_Flag<bit,Iterator,IPacket>,bool>,
- public ParserBase<Iterator,IPacket>
+ : public detail::packet::ParseIntOps<Parse_Flag<bit>,bool>,
+ public PacketParserBase
{
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Flag<bit,I,P> parser; };
- typedef Iterator byte_iterator;
-
- static unsigned bytes() { return 1; }
-
- Parse_Flag() {}
- explicit Parse_Flag(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+ Parse_Flag(data_iterator i, state_type s) : PacketParserBase(i,s,fixed_bytes) {}
///////////////////////////////////////////////////////////////////////////
typedef bool value_type;
+ static size_type const fixed_bytes = bit/8+1;
- value_type value() const { return this->i()[bit/8] & (1<<(7-(bit%8))); }
+ value_type value() const { return i()[bit/8] & (1<<(7-(bit%8))); }
void value(value_type v) {
- if (v) this->i()[0] |= 1<<(7-(bit%8));
- else this->i()[0] &= ~(1<<(7-(bit%8)));
+ if (v) i()[0] |= 1<<(7-(bit%8));
+ else i()[0] &= ~(1<<(7-(bit%8)));
}
Parse_Flag const & operator= (value_type other) { value(other); return *this; }
};
- template <unsigned bit, class Iterator, class IPacket>
- std::ostream & operator<<(std::ostream & os, Parse_Flag<bit,Iterator,IPacket> const & i)
+ template <unsigned bit>
+ inline std::ostream & operator<<(std::ostream & os, Parse_Flag<bit> const & i)
{ os << i.value(); return os; }
}
#define IH_ParseInt_ 1
// Custom includes
+#include "PacketTypes.hh"
///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
-
-namespace impl {
+namespace detail {
+namespace packet {
///////////////////////////////////////////////////////////////////////////
// Integer operators
# undef mutator
Derived const & operator ++ ()
- { derived().value( derived.value()+1 ); return derived(); }
+ { derived().value( derived().value()+1 ); return derived(); }
Derived const & operator -- ()
- { derived().value( derived.value()-1 ); return derived(); }
+ { derived().value( derived().value()-1 ); return derived(); }
- Derived const & operator ++ (int)
- { Value v (derived.value()); derived().value( v+1 ); return v; }
- Derived const & operator -- (int)
- { Value v (derived.value()); derived().value( v-1 ); return v; }
+ Value operator ++ (int)
+ { Value v (derived().value()); derived().value( v+1 ); return v; }
+ Value operator -- (int)
+ { Value v (derived().value()); derived().value( v-1 ); return v; }
private:
Derived & derived() { return *static_cast<Derived *>(this); }
///////////////////////////////////////////////////////////////////////////
// Network byte order integer extraction
- template <class Iterator>
- boost::uint16_t parse_uint16(Iterator const & i)
+ inline boost::uint16_t parse_uint16(iterator i)
{
return i[1] | i[0]<<8;
}
- template <class Iterator>
- void write_uint16(Iterator const & i, boost::uint16_t v)
+ inline void write_uint16(iterator i, boost::uint16_t v)
{
i[0] = ( v >> 8 ) & 0xff;
i[1] = ( v ) & 0xff;
}
- template <class Iterator>
- boost::uint32_t parse_uint24(Iterator const & i)
+ inline boost::uint32_t parse_uint24(iterator i)
{
return i[2] | i[1]<<8 | i[0]<<16;
}
- template <class Iterator>
- void write_uint24(Iterator const & i, boost::uint32_t v)
+ inline void write_uint24(iterator i, boost::uint32_t v)
{
i[0] = ( v >> 16 ) & 0xff;
i[1] = ( v >> 8 ) & 0xff;
i[2] = ( v ) & 0xff;
}
- template <class Iterator>
- boost::uint32_t parse_uint32(Iterator const & i)
+ inline boost::uint32_t parse_uint32(iterator i)
{
return i[3] | i[2]<<8 | i[1]<<16 | i[0]<<24;
}
- template <class Iterator>
- void write_uint32(Iterator const & i, boost::uint32_t v)
+ inline void write_uint32(iterator i, boost::uint32_t v)
{
i[0] = ( v >> 24 ) & 0xff;
i[1] = ( v >> 16 ) & 0xff;
///////////////////////////////////////////////////////////////////////////
// bitfield extraction
- template <class Iterator, unsigned offset, unsigned endb, unsigned start, unsigned end>
+ // Doxygen doesn't like this stuff ...
+
+# ifndef DOXYGEN
+
+ template <unsigned offset, unsigned endb, unsigned start, unsigned end>
struct parse_bitfield_i
{
- static boost::uint32_t parse(Iterator const & i) {
+ static boost::uint32_t parse(iterator i) {
return ( ( ( parse_uint32(i+offset+1)>>(40-end) ) // Beware of sign extension !!
& boost::low_bits_mask_t<32-(40-end)>::sig_bits )
| (i[offset]<<(32-(40-end))) )
& boost::low_bits_mask_t<end-start>::sig_bits;
}
- static void write(Iterator const & i, boost::uint32_t v) {
+ static void write(iterator i, boost::uint32_t v) {
write_uint32(i+offset+1,
(parse_uint32(i+offset+1) & ~(boost::low_bits_mask_t<end-8>::sig_bits<<(40-end)))
| ((v & boost::low_bits_mask_t<end-8>::sig_bits) << (40-end)));
}
};
- template <class Iterator, unsigned offset, unsigned start, unsigned end>
- struct parse_bitfield_i<Iterator, offset, 3, start, end>
+ template <unsigned offset, unsigned start, unsigned end>
+ struct parse_bitfield_i<offset, 3, start, end>
{
- static boost::uint32_t parse(Iterator const & i) {
+ static boost::uint32_t parse(iterator i) {
return ( parse_uint32(i+offset)>>(32-end) )
& boost::low_bits_mask_t<end-start>::sig_bits;
}
- static void write(Iterator const & i, boost::uint32_t v) {
+ static void write(iterator i, boost::uint32_t v) {
write_uint32(i+offset,
(parse_uint32(i+offset) & ~(boost::low_bits_mask_t<end-start>::sig_bits<<(32-end)))
| ((v & boost::low_bits_mask_t<end-start>::sig_bits) << (32-end)));
}
};
- template <class Iterator, unsigned offset, unsigned start, unsigned end>
- struct parse_bitfield_i<Iterator, offset, 2, start, end>
+ template <unsigned offset, unsigned start, unsigned end>
+ struct parse_bitfield_i<offset, 2, start, end>
{
- static boost::uint32_t parse(Iterator const & i) {
+ static boost::uint32_t parse(iterator i) {
return ( parse_uint24(i+offset)>>(24-end) )
& boost::low_bits_mask_t<end-start>::sig_bits;
}
- static void write(Iterator const & i, boost::uint32_t v) {
+ static void write(iterator i, boost::uint32_t v) {
write_uint24(i+offset,
(parse_uint24(i+offset) & ~(boost::low_bits_mask_t<end-start>::sig_bits<<(24-end)))
| ((v & boost::low_bits_mask_t<end-start>::sig_bits) << (24-end)));
}
};
- template <class Iterator, unsigned offset, unsigned start, unsigned end>
- struct parse_bitfield_i<Iterator, offset, 1, start, end>
+ template <unsigned offset, unsigned start, unsigned end>
+ struct parse_bitfield_i<offset, 1, start, end>
{
- static boost::uint32_t parse(Iterator const & i) {
+ static boost::uint32_t parse(iterator i) {
return ( parse_uint16(i+offset)>>(16-end) )
& boost::low_bits_mask_t<end-start>::sig_bits;
}
- static void write(Iterator const & i, boost::uint32_t v) {
+ static void write(iterator i, boost::uint32_t v) {
write_uint16(i+offset,
(parse_uint16(i+offset) & ~(boost::low_bits_mask_t<end-start>::sig_bits<<(16-end)))
| ((v & boost::low_bits_mask_t<end-start>::sig_bits) << (16-end)));
}
};
- template <class Iterator, unsigned offset, unsigned start, unsigned end>
- struct parse_bitfield_i<Iterator, offset, 0, start, end>
+ template <unsigned offset, unsigned start, unsigned end>
+ struct parse_bitfield_i<offset, 0, start, end>
{
- static boost::uint32_t parse(Iterator const & i) {
+ static boost::uint32_t parse(iterator i) {
return ( i[offset]>>(8-end) )
& boost::low_bits_mask_t<end-start>::sig_bits;
}
- static void write(Iterator const & i, boost::uint32_t v) {
+ static void write(iterator i, boost::uint32_t v) {
i[offset] = (i[offset] & ~(boost::low_bits_mask_t<end-start>::sig_bits<<(8-end)))
| ((v & boost::low_bits_mask_t<end-start>::sig_bits) << (8-end));
}
};
- template <class Iterator, unsigned start, unsigned end>
+# endif
+
+ template <unsigned start, unsigned end>
struct parse_bitfield
- : public parse_bitfield_i<Iterator,start/8,(end-1)/8-start/8,start%8,end-8*(start/8)>
+ : public parse_bitfield_i<start/8,(end-1)/8-start/8,start%8,end-8*(start/8)>
{};
-}}
+}}}
///////////////////////////////ih.e////////////////////////////////////////
#endif
// Custom includes
#include "ParseInt.hh"
-#include "Packet.hh"
+#include "PacketInterpreter.hh"
+#include "PacketType.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
using namespace senf;
+namespace {
+ struct VoidPacket : public PacketTypeBase
+ {};
+}
+
BOOST_AUTO_UNIT_TEST(parseInt_fixedSizes)
{
- unsigned char data[] = { 0x8e, 0x2f, 0x57, 0x12, 0xd1 };
- typedef unsigned char * iterator;
+ PacketInterpreterBase::byte data[] = { 0x8e, 0x2f, 0x57, 0x12, 0xd1 };
+ PacketInterpreterBase::ptr p (PacketInterpreter<VoidPacket>::create(data));
- BOOST_CHECK_EQUAL(Parse_Int8<iterator>(data).value(), -114);
- BOOST_CHECK_EQUAL(Parse_Int8<iterator>(data+1).value(), 47);
- BOOST_CHECK_EQUAL(Parse_UInt8<iterator>(data).value(), 142u);
+ BOOST_CHECK_EQUAL(Parse_Int8(p->data().begin(),&p->data()).value(), -114);
+ BOOST_CHECK_EQUAL(Parse_Int8(p->data().begin()+1,&p->data()).value(), 47);
+ BOOST_CHECK_EQUAL(Parse_UInt8(p->data().begin(),&p->data()).value(), 142u);
- BOOST_CHECK_EQUAL(Parse_Int16<iterator>(data).value(), -29137);
- BOOST_CHECK_EQUAL(Parse_Int16<iterator>(data+1).value(), 12119);
- BOOST_CHECK_EQUAL(Parse_UInt16<iterator>(data).value(), 36399u);
+ BOOST_CHECK_EQUAL(Parse_Int16(p->data().begin(),&p->data()).value(), -29137);
+ BOOST_CHECK_EQUAL(Parse_Int16(p->data().begin()+1,&p->data()).value(), 12119);
+ BOOST_CHECK_EQUAL(Parse_UInt16(p->data().begin(),&p->data()).value(), 36399u);
- BOOST_CHECK_EQUAL(Parse_Int24<iterator>(data).value(), -7458985);
- BOOST_CHECK_EQUAL(Parse_Int24<iterator>(data+1).value(), 3102482);
- BOOST_CHECK_EQUAL(Parse_UInt24<iterator>(data).value(), 9318231u);
+ BOOST_CHECK_EQUAL(Parse_Int24(p->data().begin(),&p->data()).value(), -7458985);
+ BOOST_CHECK_EQUAL(Parse_Int24(p->data().begin()+1,&p->data()).value(), 3102482);
+ BOOST_CHECK_EQUAL(Parse_UInt24(p->data().begin(),&p->data()).value(), 9318231u);
- BOOST_CHECK_EQUAL(Parse_Int32<iterator>(data).value(), -1909500142);
- BOOST_CHECK_EQUAL(Parse_Int32<iterator>(data+1).value(), 794235601);
- BOOST_CHECK_EQUAL(Parse_UInt32<iterator>(data).value(), 2385467154u);
+ BOOST_CHECK_EQUAL(Parse_Int32(p->data().begin(),&p->data()).value(), -1909500142);
+ BOOST_CHECK_EQUAL(Parse_Int32(p->data().begin()+1,&p->data()).value(), 794235601);
+ BOOST_CHECK_EQUAL(Parse_UInt32(p->data().begin(),&p->data()).value(), 2385467154u);
}
BOOST_AUTO_UNIT_TEST(parseInt_bits)
// 012345678901234567890123456789012345678901234567
// -------- -------- --------
// 011000111101011101011010001100011010010001000110
- unsigned char data[] = { 0x63, 0xd7, 0x5a, 0x31, 0xa4, 0x46 };
- typedef unsigned char * iterator;
+ PacketInterpreterBase::byte data[] = { 0x63, 0xd7, 0x5a, 0x31, 0xa4, 0x46 };
+ PacketInterpreterBase::ptr p (PacketInterpreter<VoidPacket>::create(data));
// 1 byte
- BOOST_CHECK_EQUAL((Parse_UIntField<2,7,iterator>(data).value()), 17u);
- BOOST_CHECK_EQUAL((Parse_IntField<2,7,iterator>(data).value()), -15);
- BOOST_CHECK_EQUAL((Parse_UIntField<3,7,iterator>(data).value()), 1u);
- BOOST_CHECK_EQUAL((Parse_IntField<3,7,iterator>(data).value()), 1);
- BOOST_CHECK_EQUAL((Parse_UIntField<0,8,iterator>(data).value()), 99u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<2,7>(p->data().begin(),&p->data()).value()), 17u);
+ BOOST_CHECK_EQUAL((Parse_IntField<2,7>(p->data().begin(),&p->data()).value()), -15);
+ BOOST_CHECK_EQUAL((Parse_UIntField<3,7>(p->data().begin(),&p->data()).value()), 1u);
+ BOOST_CHECK_EQUAL((Parse_IntField<3,7>(p->data().begin(),&p->data()).value()), 1);
+ BOOST_CHECK_EQUAL((Parse_UIntField<0,8>(p->data().begin(),&p->data()).value()), 99u);
// 2 byte
- BOOST_CHECK_EQUAL((Parse_UIntField<5,12,iterator>(data).value()), 61u);
- BOOST_CHECK_EQUAL((Parse_UIntField<0,12,iterator>(data).value()), 1597u);
- BOOST_CHECK_EQUAL((Parse_UIntField<8,13,iterator>(data).value()), 26u);
- BOOST_CHECK_EQUAL((Parse_UIntField<8,16,iterator>(data).value()), 215u);
- BOOST_CHECK_EQUAL((Parse_UIntField<0,16,iterator>(data).value()), 25559u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<5,12>(p->data().begin(),&p->data()).value()), 61u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<0,12>(p->data().begin(),&p->data()).value()), 1597u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<8,13>(p->data().begin(),&p->data()).value()), 26u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<8,16>(p->data().begin(),&p->data()).value()), 215u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<0,16>(p->data().begin(),&p->data()).value()), 25559u);
// 3 byte
- BOOST_CHECK_EQUAL((Parse_UIntField<6,20,iterator>(data).value()), 15733u);
- BOOST_CHECK_EQUAL((Parse_IntField<6,20,iterator>(data).value()), -651);
- BOOST_CHECK_EQUAL((Parse_UIntField<13,22,iterator>(data).value()), 470u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<6,20>(p->data().begin(),&p->data()).value()), 15733u);
+ BOOST_CHECK_EQUAL((Parse_IntField<6,20>(p->data().begin(),&p->data()).value()), -651);
+ BOOST_CHECK_EQUAL((Parse_UIntField<13,22>(p->data().begin(),&p->data()).value()), 470u);
// 4 byte
- BOOST_CHECK_EQUAL((Parse_UIntField<3,28,iterator>(data).value()), 4027811u);
- BOOST_CHECK_EQUAL((Parse_UIntField<13,38,iterator>(data).value()), 30837865u);
- BOOST_CHECK_EQUAL((Parse_UIntField<8,40,iterator>(data).value()), 3613012388u);
- BOOST_CHECK_EQUAL((Parse_IntField<8,40,iterator>(data).value()), -681954908);
+ BOOST_CHECK_EQUAL((Parse_UIntField<3,28>(p->data().begin(),&p->data()).value()), 4027811u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<13,38>(p->data().begin(),&p->data()).value()), 30837865u);
+ BOOST_CHECK_EQUAL((Parse_UIntField<8,40>(p->data().begin(),&p->data()).value()), 3613012388u);
+ BOOST_CHECK_EQUAL((Parse_IntField<8,40>(p->data().begin(),&p->data()).value()), -681954908);
// 5 byte
- BOOST_CHECK_EQUAL((Parse_UIntField<3,34,iterator>(data).value()), 257779910u);
- BOOST_CHECK_EQUAL((Parse_IntField<13,41,iterator>(data).value()), -21732536);
+ BOOST_CHECK_EQUAL((Parse_UIntField<3,34>(p->data().begin(),&p->data()).value()), 257779910u);
+ BOOST_CHECK_EQUAL((Parse_IntField<13,41>(p->data().begin(),&p->data()).value()), -21732536);
// single bit
- BOOST_CHECK_EQUAL((Parse_Flag<32,iterator>(data).value()), true);
- BOOST_CHECK_EQUAL((Parse_Flag<12,iterator>(data).value()), false);
+ BOOST_CHECK_EQUAL((Parse_Flag<32>(p->data().begin(),&p->data()).value()), true);
+ BOOST_CHECK_EQUAL((Parse_Flag<12>(p->data().begin(),&p->data()).value()), false);
}
BOOST_AUTO_UNIT_TEST(parseInt_assign)
{
- unsigned char data[] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
- typedef unsigned char * iterator;
-
- Parse_Int8<iterator>(data).value(0x2f);
- BOOST_CHECK_EQUAL( data[0], 0x2f );
-
- Parse_Int16<iterator>(data).value(0xa341);
- BOOST_CHECK_EQUAL( data[0], 0xa3 );
- BOOST_CHECK_EQUAL( data[1], 0x41 );
-
- Parse_Int24<iterator>(data).value(0x234567);
- BOOST_CHECK_EQUAL( data[0], 0x23 );
- BOOST_CHECK_EQUAL( data[1], 0x45 );
- BOOST_CHECK_EQUAL( data[2], 0x67 );
-
- Parse_Int32<iterator>(data).value(0xfedcba98);
- BOOST_CHECK_EQUAL( data[0], 0xfe );
- BOOST_CHECK_EQUAL( data[1], 0xdc );
- BOOST_CHECK_EQUAL( data[2], 0xba );
- BOOST_CHECK_EQUAL( data[3], 0x98 );
-
- Parse_IntField<2,6,iterator>(data).value(0x3);
- BOOST_CHECK_EQUAL( data[0], 0xce );
- BOOST_CHECK_EQUAL( data[1], 0xdc );
-
- Parse_IntField<6,9,iterator>(data).value(0x2);
- BOOST_CHECK_EQUAL( data[0], 0xcd );
- BOOST_CHECK_EQUAL( data[1], 0x5c );
- BOOST_CHECK_EQUAL( data[2], 0xba );
-
- Parse_IntField<2,21,iterator>(data).value(0x13d75);
- BOOST_CHECK_EQUAL( data[0], 0xc9 );
- BOOST_CHECK_EQUAL( data[1], 0xeb );
- BOOST_CHECK_EQUAL( data[2], 0xaa );
- BOOST_CHECK_EQUAL( data[3], 0x98 );
-
- Parse_UIntField<4,34,iterator>(data).value(0x268ad497u);
- BOOST_CHECK_EQUAL( (Parse_UIntField<4,34,iterator>(data).value()), 0x268ad497u );
+ PacketInterpreterBase::byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
+ PacketInterpreterBase::ptr p (PacketInterpreter<VoidPacket>::create(data));
+
+ Parse_Int8(p->data().begin(),&p->data()).value(0x2f);
+ BOOST_CHECK_EQUAL( p->data()[0], 0x2f );
+
+ Parse_Int16(p->data().begin(),&p->data()).value(0xa341);
+ BOOST_CHECK_EQUAL( p->data()[0], 0xa3 );
+ BOOST_CHECK_EQUAL( p->data()[1], 0x41 );
+
+ Parse_Int24(p->data().begin(),&p->data()).value(0x234567);
+ BOOST_CHECK_EQUAL( p->data()[0], 0x23 );
+ BOOST_CHECK_EQUAL( p->data()[1], 0x45 );
+ BOOST_CHECK_EQUAL( p->data()[2], 0x67 );
+
+ Parse_Int32(p->data().begin(),&p->data()).value(0xfedcba98);
+ BOOST_CHECK_EQUAL( p->data()[0], 0xfe );
+ BOOST_CHECK_EQUAL( p->data()[1], 0xdc );
+ BOOST_CHECK_EQUAL( p->data()[2], 0xba );
+ BOOST_CHECK_EQUAL( p->data()[3], 0x98 );
+
+ Parse_IntField<2,6>(p->data().begin(),&p->data()).value(0x3);
+ BOOST_CHECK_EQUAL( p->data()[0], 0xce );
+ BOOST_CHECK_EQUAL( p->data()[1], 0xdc );
+
+ Parse_IntField<6,9>(p->data().begin(),&p->data()).value(0x2);
+ BOOST_CHECK_EQUAL( p->data()[0], 0xcd );
+ BOOST_CHECK_EQUAL( p->data()[1], 0x5c );
+ BOOST_CHECK_EQUAL( p->data()[2], 0xba );
+
+ Parse_IntField<2,21>(p->data().begin(),&p->data()).value(0x13d75);
+ BOOST_CHECK_EQUAL( p->data()[0], 0xc9 );
+ BOOST_CHECK_EQUAL( p->data()[1], 0xeb );
+ BOOST_CHECK_EQUAL( p->data()[2], 0xaa );
+ BOOST_CHECK_EQUAL( p->data()[3], 0x98 );
+
+ Parse_UIntField<4,34>(p->data().begin(),&p->data()).value(0x268ad497u);
+ BOOST_CHECK_EQUAL( (Parse_UIntField<4,34>(p->data().begin(),&p->data()).value()), 0x268ad497u );
}
BOOST_AUTO_UNIT_TEST(parseInt_operators)
{
- unsigned char data[] = { 0x63, 0xd7, 0x5a, 0x31, 0xa4, 0x46 };
+ PacketInterpreterBase::byte data[] = { 0x63, 0xd7, 0x5a, 0x31, 0xa4, 0x46 };
+ PacketInterpreterBase::ptr p (PacketInterpreter<VoidPacket>::create(data));
- Parse_UInt24<unsigned char *> p1(data);
- Parse_UInt16<unsigned char *> p2(data+3);
+ Parse_UInt24 p1(p->data().begin(),&p->data());
+ Parse_UInt16 p2(p->data().begin()+3,&p->data());
BOOST_CHECK_EQUAL( ~p1, 4288424101u );
BOOST_CHECK ( !!p1 );
BOOST_CHECK_EQUAL( p1, 6555902u );
p2 += p1;
// Here some idiotic automatic promotion from unsigned short ->
- // int happens in the second macro parameter ... hrmpf ...
+ // int happens in the first macro parameter ... hrmpf ...
BOOST_CHECK_EQUAL( p2, 15010 );
+ BOOST_CHECK_EQUAL( ++p1, 6555903u );
+ BOOST_CHECK_EQUAL( p1++, 6555903u );
+ BOOST_CHECK_EQUAL( p1, 6555904u );
+ BOOST_CHECK_EQUAL( --p1, 6555903u );
+ BOOST_CHECK_EQUAL( p1--, 6555903u );
+ BOOST_CHECK_EQUAL( p1, 6555902u );
+
p1 = 0x123456u;
- BOOST_CHECK_EQUAL( data[0], 0x12 );
- BOOST_CHECK_EQUAL( data[1], 0x34 );
- BOOST_CHECK_EQUAL( data[2], 0x56 );
- BOOST_CHECK_EQUAL( data[3], 0x3a );
+ BOOST_CHECK_EQUAL( p->data()[0], 0x12 );
+ BOOST_CHECK_EQUAL( p->data()[1], 0x34 );
+ BOOST_CHECK_EQUAL( p->data()[2], 0x56 );
+ BOOST_CHECK_EQUAL( p->data()[3], 0x3a );
// I stop here ... this is absolutely identical for all other
// operators and all other integer types. If really some error pops
// up, I'll add a check here ...
}
-namespace {
-
- template < class P >
- class TestPacket
- : public Packet, public P::template rebind< Packet::iterator,TestPacket<P> >::parser
- {
- public:
- typedef typename P::template rebind<Packet::iterator,TestPacket>::parser parser;
- typedef typename ptr_t<TestPacket>::ptr ptr;
-
- static bool check(iterator b, iterator e) { return true; }
-
- private:
- template <class Arg>
- TestPacket(Arg const & arg)
- : Packet(arg) {}
-
- virtual void v_nextInterpreter() const {}
- virtual void v_finalize() {}
- virtual void v_dump(std::ostream &) const {}
-
- friend class Packet;
- };
-
- template < class P >
- typename P::value_type packetCheck()
- {
- unsigned char data[] = { 0x8e, 0x2f, 0x57, 0x12, 0xd1 };
- typename TestPacket<P>::ptr p (Packet::create< TestPacket<P> >(data, data+sizeof(data)));
- return p->value();
- }
-
-}
-
-BOOST_AUTO_UNIT_TEST(parseInt_inherited)
-{
- BOOST_CHECK_EQUAL(packetCheck< Parse_Int8<> >(), -114);
- BOOST_CHECK_EQUAL(packetCheck< Parse_UInt8<> >(), 142u);
-
- BOOST_CHECK_EQUAL(packetCheck< Parse_Int16<> >(), -29137);
- BOOST_CHECK_EQUAL(packetCheck< Parse_UInt16<> >(), 36399u);
-
- BOOST_CHECK_EQUAL(packetCheck< Parse_Int24<> >(), -7458985);
- BOOST_CHECK_EQUAL(packetCheck< Parse_UInt24<> >(), 9318231u);
-
- BOOST_CHECK_EQUAL(packetCheck< Parse_Int32<> >(), -1909500142);
- BOOST_CHECK_EQUAL(packetCheck< Parse_UInt32<> >(), 2385467154u);
-
- BOOST_CHECK_EQUAL((packetCheck< Parse_IntField<3,28> >()), 14873969);
- BOOST_CHECK_EQUAL((packetCheck< Parse_UIntField<3,28> >()), 14873969u);
- BOOST_CHECK_EQUAL((packetCheck< Parse_Flag<11> >()), false);
-}
-
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseList non-inline template implementation */
+
+#include "ParseList.ih"
+
+// Custom includes
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_List<ElementParser,ListPolicy>
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List<ListPolicy>::init()
+ const
+{
+ ListPolicy::init(i(),state());
+ iterator i (begin());
+ iterator const e (end());
+ for(; i!=e; ++i)
+ i->init();
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List<ListPolicy>::value_type
+senf::Parse_List<ListPolicy>::back()
+ const
+{
+ BOOST_ASSERT( ! empty() );
+ iterator i (begin()), j;
+ iterator const e (end());
+ for (j=i; i!=e; j=i, ++i) ;
+ return *j;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_List_Container<ListPolicy>
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::value_type
+senf::Parse_List_Container<ListPolicy>::back()
+ const
+{
+ BOOST_ASSERT( ! empty() );
+ iterator i (begin()), j;
+ iterator const e (end());
+ for (j=i; i!=e; j=i, ++i) ;
+ return *j;
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::shift(iterator pos, size_type n)
+{
+ ListPolicy::update(i(),state());
+ safe_data_iterator sp (data(),pos.raw());
+ safe_data_iterator si (data(),i());
+ for (; n>0; --n) {
+ data().insert(sp,senf::init_bytes<value_type>::value,0);
+ value_type(sp,state()).init();
+ ListPolicy::insert(si,state(),sp);
+ }
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List_Container<ListPolicy>::insert(iterator pos,
+ size_type n,
+ Value const & t)
+{
+ ListPolicy::update(i(),state());
+ safe_data_iterator sp (data(),pos.raw());
+ safe_data_iterator si (data(),i());
+ for (; n>0; --n) {
+ data().insert(sp,senf::init_bytes<value_type>::value,0);
+ value_type(sp,state()).init();
+ value_type(sp,state()) << t;
+ ListPolicy::insert(si,state(),sp);
+ }
+}
+
+template <class ListPolicy>
+template <class ForwardIterator>
+prefix_ void senf::Parse_List_Container<ListPolicy>::
+insert(iterator pos, ForwardIterator f, ForwardIterator l,
+ typename boost::disable_if< boost::is_convertible<ForwardIterator,size_type> >::type *)
+{
+ ListPolicy::update(i(),state());
+ safe_data_iterator sp (data(),pos.raw());
+ safe_data_iterator si (data(),i());
+ for (; f!=l; ++f) {
+ data().insert(sp,senf::init_bytes<value_type>::value,0);
+ value_type(sp,state()).init();
+ value_type(sp,state()) << *f;
+ ListPolicy::insert(si,state(),sp);
+ sp += senf::bytes(value_type(sp,state()));
+ }
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::erase(iterator pos,
+ size_type n)
+{
+ ListPolicy::update(i(),state());
+ safe_data_iterator si (data(),i());
+ safe_data_iterator sp (data(),pos.raw());
+ for (; n>0; --n) {
+ ListPolicy::erase(si,state(),sp);
+ data().erase(sp,boost::next(sp,senf::bytes(value_type(sp,state()))));
+ }
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::clear()
+{
+ size_type sz (bytes());
+ if (sz > ListPolicy::init_bytes)
+ data().erase(boost::next(i(),ListPolicy::init_bytes),boost::next(i(),sz));
+ else
+ data().insert(boost::next(i(),sz), ListPolicy::init_bytes-sz, 0u);
+ std::fill(i(),boost::next(i(),ListPolicy::init_bytes), 0u);
+ ListPolicy::init(i(),state());
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::resize(size_type n)
+{
+ size_type sz (size());
+ if (sz>n)
+ erase(boost::next(begin(),n),end());
+ else
+ push_back_space(n-sz);
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List_Container<ListPolicy>::resize(size_type n,
+ Value value)
+{
+ size_type sz (size());
+ if (sz>n)
+ erase(boost::next(begin(),n),end());
+ else
+ push_back(value,n-sz);
+}
+
+///////////////////////////////ct.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseList inline template implementation */
+
+#include "ParseList.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_List<ListPolicy>
+
+template <class ListPolicy>
+prefix_ senf::Parse_List<ListPolicy>::Parse_List(data_iterator i, state_type s)
+ : PacketParserBase(i,s), ListPolicy()
+{}
+
+template <class ListPolicy>
+prefix_ senf::Parse_List<ListPolicy>::Parse_List(ListPolicy policy,
+ data_iterator i, state_type s)
+ : PacketParserBase(i,s), ListPolicy(policy)
+{}
+
+template <class ListPolicy>
+prefix_ senf::PacketParserBase::size_type
+senf::Parse_List<ListPolicy>::bytes()
+ const
+{
+ return ListPolicy::bytes(i(),state());
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Container interface
+
+template <class ListPolicy>
+prefix_ senf::PacketParserBase::size_type
+senf::Parse_List<ListPolicy>::size()
+ const
+{
+ return ListPolicy::size(i(),state());
+}
+
+template <class ListPolicy>
+prefix_ bool senf::Parse_List<ListPolicy>::empty()
+ const
+{
+ return begin() == end();
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List<ListPolicy>::iterator
+senf::Parse_List<ListPolicy>::begin()
+ const
+{
+ return iterator(i(),state(),iterator::Begin);
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List<ListPolicy>::iterator
+senf::Parse_List<ListPolicy>::end()
+ const
+{
+ return iterator(i(),state(),iterator::End);
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List<ListPolicy>::value_type
+senf::Parse_List<ListPolicy>::front()
+ const
+{
+ BOOST_ASSERT( ! empty() );
+ return *begin();
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List<ListPolicy>::push_back(Value value, size_type n)
+ const
+{
+ container c(*this);
+ c.push_back(value,n);
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List<ListPolicy>::push_back_space(size_type n)
+ const
+{
+ container c(*this);
+ c.push_back_space(n);
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List<ListPolicy>::push_front(Value value, size_type n)
+ const
+{
+ container c(*this);
+ c.push_front(value,n);
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List<ListPolicy>::push_front_space(size_type n)
+ const
+{
+ container c(*this);
+ c.push_front_space(n);
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List<ListPolicy>::resize(size_type n)
+ const
+{
+ container c(*this);
+ c.resize(n);
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List<ListPolicy>::resize(size_type n, Value value)
+ const
+{
+ container c(*this);
+ c.resize(n,value);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::Parse_List_Iterator()
+{}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::
+Parse_List_Iterator(PacketParserBase::data_iterator i, PacketParserBase::state_type s, Begin_t)
+ : IteratorPolicy(), i_(IteratorPolicy::setBegin(i,s)), s_(s)
+{}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::
+Parse_List_Iterator(PacketParserBase::data_iterator i, PacketParserBase::state_type s, End_t)
+ : IteratorPolicy(), i_(IteratorPolicy::setEnd(i,s)), s_(s)
+{}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::
+Parse_List_Iterator(PacketParserBase::data_iterator i, PacketParserBase::state_type s,
+ PacketParserBase::data_iterator p)
+ : IteratorPolicy(), i_(p), s_(s)
+{
+ IteratorPolicy::setFromPosition(i,s,p);
+}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ senf::PacketParserBase::data_iterator
+senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::raw()
+ const
+{
+ return IteratorPolicy::raw(i_,s_);
+}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ ElementParser
+senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::dereference()
+ const
+{
+ return ElementParser(i_,s_);
+}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ bool senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::
+equal(Parse_List_Iterator const & other)
+ const
+{
+ return i_ == other.i_;
+}
+
+template <class ElementParser, class IteratorPolicy>
+prefix_ void senf::detail::Parse_List_Iterator<ElementParser,IteratorPolicy>::increment()
+{
+ i_ = IteratorPolicy::next(i_,s_);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_List_Container<ListPolicy>
+
+// Structors and default members
+
+template <class ListPolicy>
+prefix_ senf::Parse_List_Container<ListPolicy>::
+Parse_List_Container(parser_type const & list)
+ : ListPolicy(list), state_(list.state()), i_(std::distance(data().begin(),list.i()))
+{}
+
+template <class ListPolicy>
+prefix_ senf::Parse_List_Container<ListPolicy>::~Parse_List_Container()
+{
+ ListPolicy::update(i(),state());
+}
+
+// Accessors
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::size_type
+senf::Parse_List_Container<ListPolicy>::size()
+ const
+{
+ ListPolicy::update(i(),state());
+ return ListPolicy::size(i(),state());
+}
+
+template <class ListPolicy>
+prefix_ bool senf::Parse_List_Container<ListPolicy>::empty()
+ const
+{
+ ListPolicy::update(i(),state());
+ return begin() == end();
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::iterator
+senf::Parse_List_Container<ListPolicy>::begin()
+ const
+{
+ ListPolicy::update(i(),state());
+ return iterator(i(),state(),iterator::Begin);
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::iterator
+senf::Parse_List_Container<ListPolicy>::end()
+ const
+{
+ ListPolicy::update(i(),state());
+ return iterator(i(),state(),iterator::End);
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::value_type
+senf::Parse_List_Container<ListPolicy>::front()
+ const
+{
+ BOOST_ASSERT( ! empty() );
+ return *begin();
+}
+
+// Mutators
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List_Container<ListPolicy>::insert(iterator pos,
+ Value const & t)
+{
+ insert(pos,1,t);
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::erase(iterator f, iterator l)
+{
+ erase(f,std::distance(f,l));
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List_Container<ListPolicy>::push_back(Value value,
+ size_type n)
+{
+ insert(end(),n,value);
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::push_back_space(size_type n)
+{
+ shift(end(),n);
+}
+
+template <class ListPolicy>
+template <class Value>
+prefix_ void senf::Parse_List_Container<ListPolicy>::push_front(Value value,
+ size_type n)
+{
+ insert(begin(),n,value);
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::push_front_space(size_type n)
+{
+ shift(begin(),n);
+}
+
+// Parser interface
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::parser_type
+senf::Parse_List_Container<ListPolicy>::parser()
+ const
+{
+ ListPolicy::update(i(),state());
+ return parser_type(i(),state());
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::data_iterator
+senf::Parse_List_Container<ListPolicy>::i()
+ const
+{
+ return boost::next(data().begin(),i_);
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::state_type
+senf::Parse_List_Container<ListPolicy>::state()
+ const
+{
+ return state_;
+}
+
+template <class ListPolicy>
+prefix_ senf::PacketData & senf::Parse_List_Container<ListPolicy>::data()
+ const
+{
+ return *state_;
+}
+
+template <class ListPolicy>
+prefix_ typename senf::Parse_List_Container<ListPolicy>::size_type
+senf::Parse_List_Container<ListPolicy>::bytes()
+ const
+{
+ ListPolicy::update(i(),state());
+ return ListPolicy::bytes(i(),state());
+}
+
+template <class ListPolicy>
+prefix_ void senf::Parse_List_Container<ListPolicy>::init()
+ const
+{
+ parser().init();
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseList public header */
+
+#ifndef HH_ParseList_
+#define HH_ParseList_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+#include "PacketParser.hh"
+
+//#include "ParseList.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ namespace detail { template <class ElementParser, class IteratorPolicy>
+ class Parse_List_Iterator; }
+
+ template <class ListPolicy>
+ class Parse_List_Container;
+
+ /** \brief
+ */
+ template <class ListPolicy>
+ class Parse_List
+ : public PacketParserBase,
+ private ListPolicy
+ {
+ public:
+ Parse_List(data_iterator i, state_type s);
+ Parse_List(ListPolicy policy, data_iterator i, state_type s);
+
+ size_type bytes() const;
+ void init() const;
+
+ static const size_type init_bytes = ListPolicy::init_bytes;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Container interface
+
+ typedef typename ListPolicy::element_type value_type;
+ typedef detail::Parse_List_Iterator<
+ value_type, typename ListPolicy::iterator_policy > iterator;
+ typedef iterator const_iterator;
+ typedef typename ListPolicy::container_type container;
+
+ size_type size() const;
+ bool empty() const;
+
+ iterator begin() const;
+ iterator end() const;
+
+ value_type front() const;
+ value_type back() const;
+
+ template <class Value> void push_back (Value value, size_type n=1) const;
+ void push_back_space (size_type n=1) const;
+ template <class Value> void push_front (Value value, size_type n=1) const;
+ void push_front_space (size_type n=1) const;
+ void resize (size_type n) const;
+ template <class Value> void resize (size_type n, Value value) const;
+
+ private:
+ template <class Policy> friend class Parse_List_Container;
+ };
+
+ /** \brief Exmaple of a list policy. ONLY FOR EXPOSITION.
+
+ This class shows the interface which must be implemented by a list policy. It is not a list
+ policy only a declaration of the interface:
+ \code
+ tempalte <class ElementParser>
+ struct ExampleListPolicy
+ {
+ // optional typedefs used to simplify all other declarations
+ typedef PacketParserBase::data_iterator data_iterator;
+ typedef PacketParserBase::state_type state_type;
+ typedef PacketParserBase::size_type size_type;
+
+ // mandatory typedefs in the parser and container policy
+ typedef ElementParser element_type;
+ typedef Parse_List< ExampleListPolicy > parser_type;
+ typedef Parse_List_Container< ExampleListPolicy > container_type;
+
+ // mandatory constant in parser and container policy
+ static const size_type init_bytes = 0;
+
+ // Members needed in the parser and the container policy
+ size_type bytes (data_iterator i, state_type s) const;
+ size_type size (data_iterator i, state_type s) const;
+ void init (data_iterator i, state_type s) const;
+
+ // Members needed only in the container policy
+ void erase (data_iterator i, state_type s, iterator p) const;
+ void insert (data_iterator i, state_type s, iterator p) const;
+
+ struct iterator_policy
+ {
+ iterator setBegin (data_iterator i, state_type s);
+ iterator setEnd (data_iterator i, state_type s);
+ void setFromPosition (data_iterator i, state_type s, iterator p);
+ iterator next (data_iterator i, state_type s);
+ iterator raw (data_iterator i, state_type s) const;
+ };
+ };
+ \endcode
+
+ If necessary, you may use a different policy in the container_type. The ListPolicy must
+ define the elements bytes(), size() and init(), the container policy needs all theese and
+ additionally needs erase() and insert(). The container policy will also need the
+ element_type, parser_type and container_type typedefs.
+
+ \see \ref Parse_List
+ */
+ struct ExampleListPolicy
+ {
+ typedef PacketParserBase::data_iterator iterator;
+ typedef PacketParserBase::state_type state_type;
+ typedef PacketParserBase::size_type size_type;
+
+ static const size_type init_bytes = 0; ///< Size of a new list of this type
+ /**< Initial size which needs to be allocated to this type
+ of list */
+
+ size_type bytes(iterator i, state_type s) const; ///< Size of list in bytes
+ /**< Return the complete size of the list in
+ bytes. Depending on the type of list, thie call may
+ need to completely traverse the list ... */
+
+ size_type size(iterator i, state_type s) const; ///< Number of elements in list
+ /**< Return the number of elements in the list. This
+ operation may be quite inefficient for some lists (the
+ list must be traversed to find that number. */
+
+ void init(iterator i, state_type s) const; ///< Initialize new list
+ /**< Called after init_size bytes have been allocated to
+ initialize the list. After init() is called, the list
+ is traversed to initialize any members (probably
+ none) */
+
+ void erase(iterator i, state_type s, iterator p) const; ///< Erase element from list
+ /**< Delete the list element at p from the List (i,s). When
+ this operation is called, the element is still part of
+ the list. This call must update the metadata as
+ needed. The data will be removed after this call
+ returns. */
+
+ void insert(iterator i, state_type s, iterator p) const; ///< Insert element into list
+ /**< This is called after an element has been inserted at p
+ into the List (i,s) to update the metadata. */
+
+ /** \brief Example of a list iterator policy. ONLY FOR EXPOSITION.
+
+ \see \ref ExampleListPolicy \n
+ \ref Parse_List
+ */
+ struct iterator_policy
+ {
+ iterator setBegin(iterator i, state_type s); ///< Initialize iterator to begin()
+ /**< Initialize the policy from the given List (i,s). Set
+ the iterator to the beginning iterator. Return
+ data_iterator to the first element.
+
+ \warning if the list is empty, the returned iterator
+ \e must be the same as the one returned by setEnd. */
+
+ iterator setEnd(iterator i, state_type s); ///< Initialize iterator to end()
+ /**< Initialize the policy from the given List (i,s). Set
+ the iterator to the end iterator. Return data_iterator
+ used to mark the end of the range. This may be a
+ special sentinel value (e.g. data().end()) if
+ needed. */
+
+ void setFromPosition(iterator i, state_type s, iterator p);
+ ///< Initialize iterator from the given raw position
+ /**< Set the iterator to the Element at raw position p. This
+ operation can potentially be very inefficient if the
+ list needs to be traversed from the beginning until the
+ iterator is found. */
+
+ iterator next(iterator i, state_type s); ///< Advance to next element
+ /**< given an iterator to an element, go to the next
+ element. */
+
+ iterator raw(iterator i, state_type s); ///< Return raw position of element
+ /**< Given the iterator state (i,s), return the raw iterator
+ to the datum. This will be i in almost all cases EXCEPT
+ if a special sentinel value is used as end() value. In
+ this case, this member must return the real position
+ after the last element. */
+ };
+
+ /** \brief Example of a list container policy. ONLY FOR EXPOSITION
+
+ \see \ref ExampleListPolicy \n
+ \ref Parse_List
+ */
+ struct container_policy
+ {
+ void init(iterator i, state_type s); ///< Initialize new container
+ void update(iterator i, state_type s); ///< Called before every container access
+ };
+ };
+
+ template <class ListPolicy>
+ class Parse_List_Container
+ : private ListPolicy
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef typename ListPolicy::parser_type parser_type;
+ typedef PacketParserBase::data_iterator data_iterator;
+ typedef PacketParserBase::size_type size_type;
+ typedef PacketParserBase::difference_type difference_type;
+ typedef typename ListPolicy::element_type value_type;
+ typedef detail::Parse_List_Iterator<
+ value_type, typename ListPolicy::iterator_policy> iterator;
+ typedef iterator const_iterator;
+ typedef PacketParserBase::state_type state_type;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // no default constructor
+ // default copy
+ // default destructor
+ // conversion constructors
+
+ Parse_List_Container(parser_type const & list);
+ ~Parse_List_Container();
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///\name Accessors
+ ///@{
+
+ size_type size() const;
+ bool empty() const;
+
+ iterator begin() const;
+ iterator end() const;
+
+ value_type front() const;
+ value_type back() const;
+
+ ///@}
+ ///\name Mutators
+ ///@{
+
+ // All these operations can be quite inefficient depending on the list type
+ void shift(iterator pos, size_type n=1);
+ template <class Value>
+ void insert(iterator pos, Value const & t);
+ template <class Value>
+ void insert(iterator pos, size_type n, Value const & t);
+ template <class ForwardIterator>
+ void insert(iterator pos, ForwardIterator f, ForwardIterator l,
+ typename boost::disable_if< boost::is_convertible<ForwardIterator,size_type> >::type * = 0);
+
+ void erase(iterator pos, size_type n=1);
+ void erase(iterator f, iterator l);
+ void clear();
+
+ template <class Value> void push_back (Value value, size_type n=1);
+ void push_back_space (size_type n=1);
+ template <class Value> void push_front (Value value, size_type n=1);
+ void push_front_space (size_type n=1);
+ void resize (size_type n);
+ template <class Value> void resize (size_type n, Value value);
+
+ ///@}
+
+ ///\name Parser interface
+ ///@{
+
+ parser_type parser() const;
+ data_iterator i() const;
+ state_type state() const;
+ PacketData & data() const;
+
+ size_type bytes() const;
+ void init() const;
+
+ ///@}
+
+ private:
+ state_type state_;
+ size_type i_;
+ };
+
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "ParseList.cci"
+#include "ParseList.ct"
+#include "ParseList.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// comment-column: 40
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#ifndef IH_ParseListS_
-#define IH_ParseListS_ 1
+/** \file
+ \brief ParseList internal header */
+
+#ifndef IH_ParseList_
+#define IH_ParseList_ 1
// Custom includes
#include <boost/iterator/iterator_facade.hpp>
///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
+namespace detail {
-namespace impl {
-
- template <class Parser, class Sentinel, class Iterator>
- class Parse_ListS_iterator
- : public boost::iterator_facade< Parse_ListS_iterator<Parser,Sentinel,Iterator>,
- Parser,
+ template <class ElementParser, class IteratorPolicy>
+ class Parse_List_Iterator
+ : public boost::iterator_facade< Parse_List_Iterator<ElementParser,IteratorPolicy>,
+ ElementParser,
boost::forward_traversal_tag,
- Parser >
+ ElementParser >,
+ private IteratorPolicy
{
public:
- Parse_ListS_iterator();
- explicit Parse_ListS_iterator(Iterator const & i);
+ enum Begin_t { Begin };
+ enum End_t { End };
- Iterator raw() const;
+ Parse_List_Iterator();
+ Parse_List_Iterator(PacketParserBase::data_iterator i, PacketParserBase::state_type s,
+ Begin_t);
+ Parse_List_Iterator(PacketParserBase::data_iterator i, PacketParserBase::state_type s,
+ End_t);
+ Parse_List_Iterator(PacketParserBase::data_iterator i, PacketParserBase::state_type s,
+ PacketParserBase::data_iterator p);
+ PacketParserBase::data_iterator raw() const;
+
private:
friend class boost::iterator_core_access;
-
- Parser dereference() const;
- bool equal(Parse_ListS_iterator const & other) const;
+
+ ElementParser dereference() const;
+ bool equal(Parse_List_Iterator const & other) const;
void increment();
- Iterator i_;
- bool atEnd_;
+ PacketParserBase::data_iterator i_;
+ PacketParserBase::state_type s_;
};
}}
-
///////////////////////////////ih.e////////////////////////////////////////
#endif
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id: main.test.cc 206 2007-02-20 14:20:52Z g0dil $
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline non-template functions
+/** \file
+ \brief ParseList.test unit tests */
-//#include "test.hh"
-//#include "test.ih"
+//#include "ParseList.test.hh"
+//#include "ParseList.test.ih"
// Custom includes
-#define BOOST_AUTO_TEST_MAIN
+#include "ParseList.hh"
+
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
+// Since the list cannot be instantiated without a policy, there is nothing to test without atleast
+// a very simple policy. Since ParseListB provides a policy which is as simple as it can get, all
+// testing is performed in ParseListB.test.cc
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListB inline template implementation */
+
+#include "ParseListB.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::size_type
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::bytes(iterator i, state_type s)
+ const
+{
+ return BytesParser(i,s) + BytesParser::fixed_bytes;
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::size_type
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::size(iterator i, state_type s)
+ const
+{
+ parser_type l (i,s);
+ return std::distance(l.begin(),l.end());
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ void senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::init(iterator i,
+ state_type s)
+ const
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator_policy
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator_policy::
+setBegin(iterator i, state_type s)
+{
+ return boost::next(i,BytesParser::fixed_bytes);
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator_policy::
+setEnd(iterator i, state_type s)
+{
+ return boost::next(i,BytesParser(i,s) + BytesParser::fixed_bytes);
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ void
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator_policy::
+setFromPosition(iterator i, state_type s, iterator p)
+{}
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator_policy::next(iterator i,
+ state_type s)
+{
+ return boost::next(i,senf::bytes(ElementParser(i,s)));
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::iterator_policy::raw(iterator i,
+ state_type s)
+ const
+{
+ return i;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>
+
+template <class ElementParser, class BytesParser>
+prefix_
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+container_policy(parser_type const & list)
+{
+ iterator const e (boost::next(list.i(),list.bytes()));
+ iterator i (boost::next(list.i(), BytesParser::fixed_bytes));
+ for(n_=0; i!=e; ++n_, std::advance(i,ElementParser(i,list.state()).bytes())) ;
+ container_size_ = list.data().size();
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::size_type
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+bytes(iterator i, state_type s)
+ const
+{
+ return BytesParser(i,s) + BytesParser::fixed_bytes;
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ typename senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::size_type
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+size(iterator i, state_type s)
+ const
+{
+ return n_;
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ void
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+erase(iterator i, state_type s, iterator p)
+{
+ size_type b (senf::bytes(ElementParser(p,s)));
+ BytesParser(i,s) -= b;
+ --n_;
+ // The container will be reduced by b bytes directly after this call
+ container_size_ = s->size()-b;
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ void
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+insert(iterator i, state_type s, iterator p)
+{
+ BytesParser(i,s) += senf::bytes(ElementParser(p,s));
+ ++n_;
+ container_size_ = s->size();
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ void
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+init(iterator i, state_type s)
+{
+ n_ = 0;
+ container_size_ = s->size();
+}
+
+template <class ElementParser, class BytesParser>
+prefix_ void
+senf::detail::Parse_ListB_Policy<ElementParser,BytesParser>::container_policy::
+update(iterator i, state_type s)
+ const
+{
+ if (container_size_ == s->size())
+ return;
+ iterator j (boost::next(i,BytesParser::fixed_bytes));
+ for (size_type n (n_); n; --n, std::advance(j,ElementParser(j,s).bytes())) ;
+ BytesParser(i,s) = std::distance(i,j) - BytesParser::fixed_bytes;
+ container_size_ = s->size();
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListB public header */
+
+#ifndef HH_ParseListB_
+#define HH_ParseListB_ 1
+
+// Custom includes
+#include "ParseList.hh"
+
+//#include "ParseListB.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ namespace detail { template <class ElementParser, class BytesParser>
+ class Parse_ListB_Policy; }
+
+ /** \brief List parser with size-field in bytes
+
+ This list parser will parse a list which size is given by a preceding field containing the
+ lenght of the list in bytes. This struct is just a template typedef:
+ \code
+ typedef senf::Parse_VectorN< Parser_UInt32, Parser_UInt16 >::parser Parse_MyVector;
+ typedef senf::Parse_ListB< Parse_MyVector, Parse_UInt16 >::parser Parse_MyList;
+ \endcode
+ This first defines a Vector of 32 bit unsigned integers with 16 bit length counter. Then it
+ defines a list of such vectors with a 16 bit bytes field.
+
+ \warning There are some caveats when working with this kind of list
+ \li You may <b>only change the size of a contained element from a container wrapper</b>.
+ \li While you hold a container wrapper, <b>only access the packet through this wrapper</b>
+ or a nested wrepper either for reading or writing.
+
+ If lists are nested, you need to allocate a container wrapper for each level and may only
+ access the packet through the lowest-level active container wrapper.
+
+ \implementation These restrictions are necessary to ensure correct recalculation of the
+ <tt>bytes</tt> field. For more info, see the comments in \ref ParseListB.ih
+ */
+ template <class ElementParser, class BytesParser>
+ struct Parse_ListB {
+ typedef Parse_List< detail::Parse_ListB_Policy<ElementParser,BytesParser> > parser;
+ };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "ParseListB.cci"
+//#include "ParseListB.ct"
+#include "ParseListB.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListB internal header */
+
+#ifndef IH_ParseListB_
+#define IH_ParseListB_ 1
+
+// Custom includes
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace detail {
+
+ /** \brief ListPolicy defing the Parse_ListB parser
+ \internal
+ \see \ref Parse_ListB
+ */
+ template <class ElementParser, class BytesParser>
+ struct Parse_ListB_Policy
+ {
+ // This policy needs to work around a serious problem with this type of list: When we change
+ // the size of any (direct or indirect) subelement of the list, This will change will render
+ // the list completely invalid and unparseable since the 'byte' field will now be invalid.
+ //
+ // The solution we apply is to store the *size* (i.e. the number of elements) of the list
+ // when creating the container wrapper. We also maintain this value accross insert/erase
+ // statements. Additionally we also safe the complete size of the data container (the vector
+ // holding the bytes). Since we only allow packet changes through this container while it
+ // exists, any change in the container size must be a change within this list and therefore
+ // mandates an update of the 'bytes' field.
+ //
+ // The list container wrapper will call 'update' policy member before every access to the
+ // container and also in the destructor. This gives us a chance to fix the bytes header
+ // before the invalid header is seen by anyone (This is so, since we only allow access to
+ // the list through the container wrapper ...). Since we know the number of list elements,
+ // we can always find the correct 'bytes' value by traversing the list for that number of
+ // elements.
+ //
+ // By caching the container size, all this can be made reasonably efficient and usable: The
+ // updates are done automatically by only if needed. It would of course be more efficient to
+ // just apply the size change directly to the bytes header (no need to traverse the
+ // list). However, the implementation of this approach would be much more complex and even
+ // more invasive and would probably suffer from the same restrictions to the user.
+
+ struct container_policy;
+
+ typedef PacketParserBase::data_iterator iterator;
+ typedef PacketParserBase::state_type state_type;
+ typedef PacketParserBase::size_type size_type;
+ typedef ElementParser element_type;
+ typedef Parse_List< Parse_ListB_Policy > parser_type;
+ typedef Parse_List_Container< container_policy > container_type;
+
+ static const size_type init_bytes = BytesParser::fixed_bytes;
+
+ size_type bytes (iterator i, state_type s) const;
+ size_type size (iterator i, state_type s) const;
+ void init (iterator i, state_type s) const;
+
+ struct iterator_policy
+ {
+ iterator setBegin (iterator i, state_type s);
+ iterator setEnd (iterator i, state_type s);
+ void setFromPosition (iterator i, state_type s, iterator p);
+ iterator next (iterator i, state_type s);
+ iterator raw (iterator i, state_type s) const;
+ };
+
+ struct container_policy
+ {
+ typedef typename Parse_ListB_Policy<
+ ElementParser,BytesParser>::iterator_policy iterator_policy;
+ typedef typename Parse_ListB_Policy<
+ ElementParser,BytesParser>::parser_type parser_type;
+ typedef typename Parse_ListB_Policy<
+ ElementParser,BytesParser>::element_type element_type;
+
+ static const size_type init_bytes = Parse_ListB_Policy<
+ ElementParser,BytesParser>::init_bytes;
+
+ container_policy(parser_type const & list);
+
+ size_type bytes (iterator i, state_type s) const;
+ size_type size (iterator i, state_type s) const;
+ void erase (iterator i, state_type s, iterator p);
+ void insert (iterator i, state_type s, iterator p);
+ void init (iterator i, state_type s);
+ void update (iterator i, state_type s) const;
+
+ size_type n_;
+ mutable size_type container_size_;
+ };
+ };
+
+}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListB.test unit tests */
+
+//#include "ParseListB.test.hh"
+//#include "ParseListB.test.ih"
+
+// Custom includes
+#include "ParseListB.hh"
+#include "ParseVec.hh"
+#include "PacketType.hh"
+#include "ParseInt.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase
+ {};
+
+ typedef senf::Parse_VectorN<senf::Parse_UInt16,senf::Parse_UInt8>::parser ParseVec;
+ typedef senf::Parse_ListB<ParseVec,senf::Parse_UInt16>::parser ParseList;
+}
+
+BOOST_AUTO_UNIT_TEST(parseListB)
+{
+ senf::PacketInterpreterBase::ptr pi (senf::PacketInterpreter<VoidPacket>::create(
+ ParseList::init_bytes));
+
+ ParseList p (pi->data().begin(),&pi->data());
+ p.init();
+ BOOST_CHECK_EQUAL( p.size(), 0u );
+ BOOST_CHECK_EQUAL( p.bytes(), 2u );
+ BOOST_CHECK( p.empty() );
+ BOOST_CHECK( p.begin() == p.end() );
+
+ // the mutators are really tested together with the container wrappers since they are based
+ // on the container wrapper. Here we only need one call to make the list larger ...
+
+ p.push_back_space();
+ p = ParseList(pi->data().begin(),&pi->data());
+ BOOST_CHECK_EQUAL( p.bytes(), 3u );
+ BOOST_CHECK_EQUAL( p.size(), 1u );
+ BOOST_CHECK( ! p.empty() );
+ BOOST_CHECK( p.begin() != p.end() );
+}
+
+BOOST_AUTO_UNIT_TEST(parseListB_container)
+{
+ senf::PacketInterpreterBase::ptr pi (senf::PacketInterpreter<VoidPacket>::create(
+ ParseList::init_bytes));
+
+ {
+ ParseList::container c (ParseList(pi->data().begin(),&pi->data()));
+
+ BOOST_CHECK_EQUAL( c.size(), 0u );
+ BOOST_CHECK_EQUAL( c.bytes(), 2u );
+ BOOST_CHECK( c.begin() == c.end() );
+
+ c.shift(c.begin());
+ BOOST_CHECK_EQUAL( c.size(), 1u );
+ BOOST_CHECK_EQUAL( c.bytes(), 3u );
+
+ BOOST_CHECK_EQUAL( c.front().size(), 0u );
+ c.front().push_back(0x1234u);
+ BOOST_CHECK_EQUAL( c.bytes(), 5u );
+
+ {
+ senf::PacketInterpreterBase::ptr pi2 (senf::PacketInterpreter<VoidPacket>::create(
+ ParseList::init_bytes));
+ ParseList::container c2 (ParseList(pi2->data().begin(),&pi2->data()));
+ c2.push_back_space();
+ {
+ ParseVec::container c2v (c2.front());
+ c2v.push_back(0x2345u);
+ c2v.push_back(0x3456u);
+ }
+
+ BOOST_CHECK_EQUAL(c2.size(), 1u);
+ BOOST_CHECK_EQUAL(c2.bytes(), 7u);
+
+ c.insert(c.end(),c2.back());
+ BOOST_CHECK_EQUAL( c.size(), 2u );
+ BOOST_CHECK_EQUAL( c.bytes(), 10u );
+ BOOST_CHECK_EQUAL( c.back()[0], 0x2345u );
+ BOOST_CHECK_EQUAL( c.back().bytes(), c2.back().bytes() );
+
+ c2.back()[0] << 0x1357u;
+ c.insert(boost::next(c.begin()), 2u, c2.back());
+ BOOST_CHECK_EQUAL( c.size(), 4u );
+ BOOST_CHECK_EQUAL( c.bytes(), 20u );
+ BOOST_CHECK_EQUAL( (*boost::next(c.begin()))[0], 0x1357u );
+ BOOST_CHECK_EQUAL( (*boost::next(c.begin(),2))[0], 0x1357u );
+
+ c2.back()[0] << 0x2468u;
+ c.insert(c.begin(),c2.begin(),c2.end());
+ BOOST_CHECK_EQUAL( c.size(), 5u );
+ BOOST_CHECK_EQUAL( c.bytes(), 25u );
+ BOOST_CHECK_EQUAL( c.front()[0], 0x2468u );
+
+ c.erase(c.begin(),2);
+ BOOST_CHECK_EQUAL( c.size(), 3u );
+ BOOST_CHECK_EQUAL( c.bytes(), 17u );
+ BOOST_CHECK_EQUAL( c.front()[0],0x1357u );
+ BOOST_CHECK_EQUAL( c.back()[0], 0x2345u );
+
+ c.erase((boost::next(c.begin(),2)),c.end());
+ BOOST_CHECK_EQUAL( c.size(), 2u );
+ BOOST_CHECK_EQUAL( c.bytes(), 12u );
+ BOOST_CHECK_EQUAL( c.front()[0],0x1357u );
+ BOOST_CHECK_EQUAL( c.back()[0], 0x1357u );
+
+ c.clear();
+ BOOST_CHECK_EQUAL( c.size(), 0u );
+ BOOST_CHECK_EQUAL( c.bytes(), 2u );
+ }
+ }
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of non-inline template functions
+/** \file
+ \brief ParseListN non-inline template implementation */
-//#include "GenericPacket.ih"
+#include "ParseListN.ih"
// Custom includes
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::v_nextInterpreter()
- const
+template <class ElementParser, class SizeParser>
+prefix_ void
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator_policy::
+setFromPosition(iterator i, state_type s, iterator p)
{
- this->registerInterpreter<DataPacket>(this->end_header(), this->begin_trailer());
+ l_ = i;
+ if (p == data(s).end()) {
+ n_ = 0;
+ return;
+ }
+ n_ = SizeParser(i,s);
+ iterator j (boost::next(i,SizeParser::fixed_bytes));
+ for (; n_; --n_, j += ElementParser(j,s).bytes())
+ if (j==p)
+ return;
+ BOOST_ASSERT( false );
}
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::v_finalize()
-{}
-
-template <unsigned HEADER, unsigned TRAILER>
-prefix_ void senf::GenericPacket<HEADER,TRAILER>::v_dump(std::ostream & os)
+template <class ElementParser, class SizeParser>
+prefix_ typename senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator_policy::raw(iterator i,
+ state_type s)
const
{
- /// \todo implement v_dump()
+ if (i != data(s).end())
+ return i;
+ size_type n (SizeParser(l_,s));
+ iterator j (boost::next(l_,SizeParser::fixed_bytes));
+ for (; n; --n)
+ j += ElementParser(j,s).bytes();
+ return j;
}
///////////////////////////////ct.e////////////////////////////////////////
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListN inline template implementation */
+
+#include "ParseListN.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+template <class ElementParser, class SizeParser>
+prefix_ typename senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::size_type
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::bytes(iterator i, state_type s)
+ const
+{
+ return std::distance(i,parser_type(i,s).end().raw());
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ typename senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::size_type
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::size(iterator i, state_type s)
+ const
+{
+ return SizeParser(i,s);
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ void senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::init(iterator i,
+ state_type s)
+ const
+{}
+
+template <class ElementParser, class SizeParser>
+prefix_ void senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::erase(iterator i,
+ state_type s,
+ iterator p)
+ const
+{
+ --SizeParser(i,s);
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ void senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::insert(iterator i,
+ state_type s,
+ iterator p)
+ const
+{
+ ++SizeParser(i,s);
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ void senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::update(iterator i,
+ state_type s)
+ const
+{}
+
+template <class ElementParser, class SizeParser>
+prefix_ typename senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator_policy::
+setBegin(iterator i, state_type s)
+{
+ l_ = i;
+ n_ = SizeParser(i,s);
+ return n_ ? boost::next(i,SizeParser::fixed_bytes) : data(s).end();
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ typename senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator_policy::
+setEnd(iterator i, state_type s)
+{
+ l_ = i;
+ n_ = 0;
+ return data(s).end();
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ typename senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::iterator_policy::next(iterator i,
+ state_type s)
+{
+ --n_;
+ return n_ ? boost::next(i,senf::bytes(ElementParser(i,s))) : data(s).end();
+}
+
+template <class ElementParser, class SizeParser>
+prefix_ senf::PacketData &
+senf::detail::Parse_ListN_Policy<ElementParser,SizeParser>::data(state_type s)
+{
+ return *s;
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#ifndef HH_docstub_
-#define HH_docstub_ 1
+/** \file
+ \brief ParseListN public header */
+
+#ifndef HH_ParseListN_
+#define HH_ParseListN_ 1
// Custom includes
+#include "ParseList.hh"
-//#include "docstub.mpp"
+//#include "ParseListN.mpp"
///////////////////////////////hh.p////////////////////////////////////////
-namespace boost {
+namespace senf {
- struct noncopyable {};
- template <class Derived> struct totally_ordered {};
- template <class Derived, class Value, class Traversal, class Reference> struct iterator_facade {};
- template <class T> struct intrusive_ptr { T * ptr; };
- template <class T> struct shared_ptr { T * ptr; };
-
-}
+ namespace detail { template <class ElementParser, class SizeParser>
+ class Parse_ListN_Policy; }
-namespace std {
-
- struct exception {};
- template <class T> struct vector { T * elements; };
- template <class T> struct list { T * elements; };
+ template <class ElementParser, class SizeParser>
+ struct Parse_ListN {
+ typedef Parse_List< detail::Parse_ListN_Policy<ElementParser,SizeParser> > parser;
+ };
}
///////////////////////////////hh.e////////////////////////////////////////
-//#include "docstub.cci"
-//#include "docstub.ct"
-//#include "docstub.cti"
+//#include "ParseListN.cci"
+#include "ParseListN.ct"
+#include "ParseListN.cti"
#endif
\f
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListN internal header */
+
+#ifndef IH_ParseListN_
+#define IH_ParseListN_ 1
+
+// Custom includes
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace detail {
+
+ template <class ElementParser, class SizeParser>
+ struct Parse_ListN_Policy
+ {
+ typedef PacketParserBase::data_iterator iterator;
+ typedef PacketParserBase::state_type state_type;
+ typedef PacketParserBase::size_type size_type;
+ typedef ElementParser element_type;
+ typedef Parse_List< Parse_ListN_Policy > parser_type;
+ typedef Parse_List_Container< Parse_ListN_Policy > container_type;
+
+ static const size_type init_bytes = SizeParser::fixed_bytes;
+
+ size_type bytes (iterator i, state_type s) const;
+ size_type size (iterator i, state_type s) const;
+ void init (iterator i, state_type s) const;
+ void erase (iterator i, state_type s, iterator p) const;
+ void insert (iterator i, state_type s, iterator p) const;
+ void update (iterator i, state_type s) const;
+
+ struct iterator_policy
+ {
+ iterator setBegin (iterator i, state_type s);
+ iterator setEnd (iterator i, state_type s);
+ void setFromPosition (iterator i, state_type s, iterator p);
+ iterator next (iterator i, state_type s);
+ iterator raw (iterator i, state_type s) const;
+
+ size_type n_;
+ iterator l_;
+ };
+
+ static PacketData & data(state_type s);
+ };
+
+}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief ParseListN.test unit tests */
+
+//#include "ParseListN.test.hh"
+//#include "ParseListN.test.ih"
+
+// Custom includes
+#include "ParseListN.hh"
+#include "ParseVec.hh"
+#include "ParseInt.hh"
+#include "PacketType.hh"
+#include "Packet.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+ struct VoidPacket_Type : public senf::PacketTypeBase
+ {};
+ typedef senf::ConcretePacket<VoidPacket_Type> VoidPacket;
+}
+
+BOOST_AUTO_UNIT_TEST(parseListN)
+{
+ typedef senf::Parse_VectorN<senf::Parse_UInt16,senf::Parse_UInt8>::parser ParseVec;
+ typedef senf::Parse_ListN<ParseVec,senf::Parse_UInt16>::parser ParseList;
+
+ VoidPacket vp (VoidPacket::create(ParseList::init_bytes));
+
+ {
+ ParseList p (vp.data().begin(),&vp.data());
+ p.init();
+ BOOST_CHECK_EQUAL( p.size(), 0u );
+ BOOST_CHECK_EQUAL( p.bytes(), 2u );
+ BOOST_CHECK( p.empty() );
+ BOOST_CHECK( p.begin() == p.end() );
+ }
+
+ {
+# define p ParseList(vp.data().begin(),&vp.data())
+
+ p.push_back_space();
+ BOOST_CHECK_EQUAL( p.bytes(), 3u );
+ BOOST_CHECK_EQUAL( p.size(), 1u );
+ BOOST_CHECK_EQUAL( p.front().bytes(), 1u );
+ BOOST_CHECK_EQUAL( p.front().size(), 0u );
+ BOOST_CHECK_EQUAL( vp.data()[1], 0x01u );
+
+ p.front().push_back(0x1234u);
+ BOOST_CHECK_EQUAL( p.front().size(), 1u );
+ BOOST_CHECK_EQUAL( p.front().bytes(), 3u );
+ BOOST_CHECK_EQUAL( p.front()[0], 0x1234u );
+ BOOST_CHECK_EQUAL( p.size(), 1u );
+ BOOST_CHECK_EQUAL( p.bytes(), 5u );
+
+ p.front().push_back(0x2345u);
+ BOOST_CHECK_EQUAL( p.front().back(), 0x2345u );
+ BOOST_CHECK_EQUAL( p.bytes(), 7u );
+
+ p.push_back_space();
+ BOOST_CHECK_EQUAL( p.size(), 2u );
+ BOOST_CHECK_EQUAL( p.bytes(), 8u );
+
+ p.back().push_front(0x0123u);
+ BOOST_CHECK_EQUAL( p.front().size(), 2u );
+ BOOST_CHECK_EQUAL( p.back().size(), 1u );
+
+ p.push_front_space(2u);
+ BOOST_CHECK_EQUAL( p.size(), 4u );
+ BOOST_CHECK_EQUAL( p.front().size(), 0u);
+
+ p.resize(3u);
+ BOOST_CHECK_EQUAL( p.size(), 3u );
+ BOOST_CHECK_EQUAL( p.back()[0], 0x1234u );
+ BOOST_CHECK_EQUAL( p.bytes(), 9u );
+
+# undef p
+ }
+}
+
+BOOST_AUTO_UNIT_TEST(parseListN_container)
+{
+ typedef senf::Parse_VectorN<senf::Parse_UInt16,senf::Parse_UInt8>::parser ParseVec;
+ typedef senf::Parse_ListN<ParseVec,senf::Parse_UInt16>::parser ParseList;
+
+ VoidPacket vp (VoidPacket::create(ParseList::init_bytes));
+
+ ParseList(vp.data().begin(),&vp.data()).init();
+
+
+}
+
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of non-inline template functions
-
-#include "ParseListS.ih"
-
-// Custom includes
-#include <algorithm>
-
-#define prefix_
-///////////////////////////////ct.p////////////////////////////////////////
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ unsigned senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::bytes()
- const
-{
- iterator i (begin());
- iterator e (end());
- size_type s (0);
- for (; i!=e; ++i)
- s += i->bytes();
- // The sentinel is not part of the range
- // but it's part of the list !!
- return s+i->bytes();
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ bool
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::check(Iterator const & e)
- const
-{
- byte_iterator i (this->i());
- for (;;) {
- value_type v (i);
- if (!v.check(e)) return false;
- if (sentinel::check(v)) return true;
- size_type s (v.bytes());
- if (s==0) return false;
- i += s;
- }
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ void senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::init()
- const
-{
- iterator i (begin());
- iterator e (end());
- for (;i!=e; ++i)
- i->init();
- // The sentinel is not part of the range
- // but it's part of the list !!
- i->init();
-}
-
-///////////////////////////////////////////////////////////////////////////
-// senf::Parse_ListS_wrapper<Parser,Sentinel,Container>
-
-template <class Parser, class Sentinel, class Container>
-template <class Value>
-prefix_ void
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::insert(iterator pos,
- Value const & t)
-{
- size_type ix (pos.raw()-container_.begin());
- container_.insert(pos.raw(),t.bytes(),0);
- Parser(container_.begin()+ix).value(t);
-}
-
-template <class Parser, class Sentinel, class Container>
-template <class Value>
-prefix_ void
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::insert(iterator pos, size_type n,
- Value const & t)
-{
- size_type ix (pos.raw()-container_.begin());
- container_.insert(pos.raw(),n*t.bytes(),0);
- typename Container::iterator i (container_.begin()+ix);
- for (; n; ++i, --n)
- Parser(i).value(t);
-}
-
-template <class Parser, class Sentinel, class Container>
-template <class InputIterator>
-prefix_ void
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::insert(iterator pos,
- InputIterator f,
- InputIterator l)
-{
- /** \todo Optimize this for random-access and multi-pass iterators */
- for (;f!=l;++f,++pos) insert(pos,*f);
-}
-
-///////////////////////////////ct.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of inline template functions
-
-#include "ParseListS.ih"
-
-// Custom includes
-#include <boost/assert.hpp>
-
-#define prefix_ inline
-///////////////////////////////cti.p///////////////////////////////////////
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::Parse_ListS()
-{}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::Parse_ListS(Iterator const & i)
- : ParserBase<Iterator,IPacket>(i)
-{}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ typename senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::size_type
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::size()
- const
-{
- return std::distance(begin(),end());
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ bool senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::empty()
- const
-{
- return begin()==end();
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ typename senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::iterator
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::begin()
- const
-{
- return iterator(this->i());
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ typename senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::iterator
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::end()
- const
-{
- return iterator();
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ typename senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::range_type
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::range()
- const
-{
- return std::make_pair(begin(),end());
-}
-
-template <class Parser, class Sentinel, class Iterator, class IPacket>
-prefix_ typename senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::range_type
-senf::Parse_ListS<Parser,Sentinel,Iterator,IPacket>::value()
- const
-{
- return range();
-}
-
-///////////////////////////////////////////////////////////////////////////
-// senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>
-
-template <class Parser, class Sentinel, class Iterator>
-prefix_
-senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>::Parse_ListS_iterator()
- : i_(), atEnd_(true)
-{}
-
-template <class Parser, class Sentinel, class Iterator>
-prefix_
-senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>::
-Parse_ListS_iterator(Iterator const & i)
- : i_(i), atEnd_(false)
-{
- atEnd_ = Sentinel::check(dereference());
-}
-
-template <class Parser, class Sentinel, class Iterator>
-prefix_ Iterator senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>::raw()
- const
-{
- return i_;
-}
-
-template <class Parser, class Sentinel, class Iterator>
-prefix_ Parser
-senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>::dereference()
- const
-{
- return Parser(i_);
-}
-
-template <class Parser, class Sentinel, class Iterator>
-prefix_ bool senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>::
-equal(Parse_ListS_iterator const & other)
- const
-{
- // !! We cannot compare the to iterators if either
- // !! Iterator is atEnd_, since one of the iterators
- // !! might be a default-constructed iterator and
- // !! iterators can only be compared with each other
- // !! if both point to the *same* valid container
- if (atEnd_ || other.atEnd_) return atEnd_ == other.atEnd_;
- return i_ == other.i_;
-}
-
-template <class Parser, class Sentinel, class Iterator>
-prefix_ void senf::impl::Parse_ListS_iterator<Parser,Sentinel,Iterator>::increment()
-{
- BOOST_ASSERT( !atEnd_ );
- i_ += dereference().bytes();
- atEnd_ = Sentinel::check(dereference());
-}
-
-///////////////////////////////////////////////////////////////////////////
-// senf::Parse_ListS_wrapper<Parser,Sentinel,Container>
-
-template <class Parser, class Sentinel, class Container>
-template <class P, class S, class I, class IP>
-prefix_ senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::
-Parse_ListS_wrapper(Parse_ListS<P,S,I,IP> const & list, Container & container)
- : i_(list.i()-container.begin()), container_(container)
-{}
-
-template <class Parser, class Sentinel, class Container>
-prefix_ typename senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::size_type
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::size()
- const
-{
- return std::distance(begin(),end());
-}
-
-template <class Parser, class Sentinel, class Container>
-prefix_ bool senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::empty()
- const
-{
- return begin()==end();
-}
-
-template <class Parser, class Sentinel, class Container>
-prefix_ typename senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::iterator
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::begin()
- const
-{
- return iterator(container_.begin()+i_);
-}
-
-template <class Parser, class Sentinel, class Container>
-prefix_ typename senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::iterator
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::end()
- const
-{
- return iterator();
-}
-
-template <class Parser, class Sentinel, class Container>
-prefix_ typename senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::range_type
-senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::range()
- const
-{
- return std::make_pair(begin(),end());
-}
-
-///////////////////////////////cti.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-/** \file
-
- \idea Add an optional state to the sentinel and an optional
- transition function. See ParseListS.hh for more.
-
- We should write a baseclass for sentinels which has no \c check()
- member, an empty \c next() member and \c void as the state
- type. This simplifies writing simple sentinels.
-
- The parse_listS iterator will have to pass the state in addition
- to the current list element to \c check(). The \c next() member
- will be invoked to advance the iterator. It is passer the current
- element and a (non-const) reference to the state which it may
- update. The Parse_ListS constructor must take an arbitrary number
- of additional arguments which are forwarded to the state
- initialization.
-
- This structure makes it simple to optimize away the overhead if
- the state type is void. If we would always instantiate the
- sentinel, this will always take up space.
-
- Another possibility would be to always instantiate the sentinel
- and make the baseclass mandatory. The baseclass would then hold
- the current raw iterator. The iterator itself would ONLY include a
- single sentinel instance .. I think, this is the best solution,
- sentinel members then have intrinsic access to the
- state. Arguments are forwarded from the list constructor to the
- Sentinel constructor.
- */
-
-#ifndef HH_ParseListS_
-#define HH_ParseListS_ 1
-
-// Custom includes
-#include <utility> // for std::pair
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/utility.hpp> // for boost::noncopyable
-#include "ParserBase.hh"
-
-//#include "ParseListS.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-
-
- template <class Parser, class Sentinel, class Container> class Parse_ListS_wrapper;
- namespace impl {
- template <class Parser, class Sentinel, class Container> class Parse_ListS_iterator;
- }
-
- template <class Parser, class Sentinel, class Iterator=nil, class IPacket=nil>
- struct Parse_ListS : public ParserBase<Iterator,IPacket>
- {
- ///////////////////////////////////////////////////////////////////////////
- // Parser interface
-
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_ListS<Parser,Sentinel,I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_ListS();
- Parse_ListS(Iterator const & i);
-
- unsigned bytes() const;
- bool check(Iterator const & e) const;
- void init() const;
-
- ///////////////////////////////////////////////////////////////////////////
- // Container interface
-
- typedef typename Parser::template rebind<Iterator>::parser value_type;
- typedef Sentinel sentinel;
- typedef impl::Parse_ListS_iterator<value_type,sentinel,byte_iterator> iterator;
- typedef unsigned size_type;
- typedef int difference_type;
- typedef std::pair<iterator,iterator> range_type;
-
- template <class Container>
- struct wrapper { typedef Parse_ListS_wrapper<value_type, Sentinel, Container> t; };
-
- size_type size() const;
- bool empty() const;
-
- iterator begin() const;
- iterator end() const;
- range_type range() const;
- range_type value() const;
-
- private:
- template <class P, class S, class C> friend class Parse_ListS_wrapper;
- };
-
- /** \brief
-
- Holds a reference to the container !
- */
- template <class Parser, class Sentinel, class Container>
- class Parse_ListS_wrapper
- : public boost::noncopyable
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef Container container;
- typedef Sentinel sentinel;
- typedef typename Parser::byte_iterator byte_iterator;
- typedef Parser value_type;
- typedef impl::Parse_ListS_iterator<value_type,sentinel,byte_iterator> iterator;
- typedef unsigned size_type;
- typedef int difference_type;
- typedef std::pair<iterator,iterator> range_type;
-
- ///////////////////////////////////////////////////////////////////////////
- ///\name Structors and default members
- ///@{
-
- template <class P, class S, class I, class IP>
- Parse_ListS_wrapper(Parse_ListS<P,S,I,IP> const & list, Container & container);
-
- // no default constructor
- // no copy
- // default destructor
- // no conversion constructors
-
- ///@}
- ///////////////////////////////////////////////////////////////////////////
- ///\name Accessors
- ///@{
-
- size_type size() const;
- bool empty() const;
-
- iterator begin() const;
- iterator end() const;
- range_type range() const;
-
- ///@}
- ///////////////////////////////////////////////////////////////////////////
- ///\name Mutators
- ///@{
-
- template <class Value> void insert(iterator pos, Value const & t);
- template <class Value> void insert(iterator pos, size_type n, Value const & t);
- template <class InputIterator> void insert(iterator pos, InputIterator f, InputIterator l);
-
- void erase(iterator pos, size_type n=1);
- void erase(iterator f, iterator l);
- void clear();
-
- ///@}
-
- protected:
-
- private:
-
- size_type i_;
- Container & container_;
- };
-
-}
-
-///////////////////////////////hh.e////////////////////////////////////////
-//#include "ParseListS.cci"
-#include "ParseListS.ct"
-#include "ParseListS.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Unit tests
-
-//#include "ParseListS.test.hh"
-//#include "ParseListS.test.ih"
-
-// Custom includes
-#include "ParseListS.hh"
-#include "ParseInt.hh"
-#include "ParseVec.hh"
-
-#include <boost/test/auto_unit_test.hpp>
-#include <boost/test/test_tools.hpp>
-#include <boost/assign.hpp>
-
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-using namespace senf;
-
-namespace {
- template <class Value>
- struct Sentinel_IsZero {
- static bool check(Value v) { return v==0; }
- };
-}
-
-BOOST_AUTO_UNIT_TEST(parse_ListS_simple)
-{
- unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x00 };
- typedef unsigned char * iterator;
- typedef Parse_ListS<Parse_UInt8<>,Sentinel_IsZero<unsigned char>,iterator> Parse_UInt8ListS;
-
- Parse_UInt8ListS l (data);
- Parse_UInt8ListS::iterator i (l.begin());
- Parse_UInt8ListS::iterator e (l.end());
- for (iterator c (data); *c; ++c) {
- BOOST_REQUIRE( i!=e );
- BOOST_CHECK_EQUAL( *c, *i );
- ++i;
- }
- BOOST_CHECK( i==e );
-
- BOOST_CHECK_EQUAL( l.bytes(), 5u );
- BOOST_CHECK_EQUAL( l.size(), 4u );
- BOOST_CHECK( !l.empty() );
-}
-
-namespace {
- // LVec is a vector with the length living directly before the vector
- template <class Parser, class SizeParser, class Iterator=nil, class IPacket=nil>
- struct Parse_LVec
- : public Parse_Vector<Parser, SizeParser,Iterator,IPacket>
- {
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_LVec<Parser,SizeParser,I,P> parser; };
- typedef typename SizeParser::template rebind<Iterator>::parser sizeParser;
-
- Parse_LVec(Iterator const & i)
- : Parse_Vector<Parser,SizeParser,Iterator,IPacket>(sizeParser(i),i+sizeParser::bytes())
- {}
-
- unsigned bytes() const
- { return this->Parse_Vector<Parser,SizeParser,Iterator,IPacket>::bytes() + sizeParser::bytes(); }
- bool check(Iterator const & e) const
- // BEWARE .. this->i() points to the Vector not the SizeParser ... hrmpf ...
- { return e>=this->i() && static_cast<unsigned>(e-this->i())+sizeParser::bytes() >= bytes(); }
- };
-
- template <class Array>
- struct Sentinel_EmptyArray {
- static bool check(Array a) { return a.empty(); }
- };
-}
-
-BOOST_AUTO_UNIT_TEST(parse_ListS_complex)
-{
- unsigned char data[] = { 0x02, 0x01, 0x02,
- 0x03, 0x11, 0x12, 0x13,
- 0x04, 0x21, 0x22, 0x23, 0x24,
- 0x00 };
-
- typedef unsigned char * iterator;
- typedef Parse_LVec<Parse_UInt8<>,Parse_UInt8<>,iterator> Parse_UInt8LVec;
- typedef Parse_ListS<Parse_UInt8LVec,Sentinel_EmptyArray<Parse_UInt8LVec>,iterator> Parse_UInt8LVecListS;
-
- Parse_UInt8LVecListS l (data);
- BOOST_CHECK( l.check(data+13) );
-
- Parse_UInt8LVecListS::iterator i (l.begin());
- Parse_UInt8LVecListS::iterator e (l.end());
- for (unsigned n (0); n<3; ++n) {
- BOOST_REQUIRE( i!=e );
- BOOST_CHECK_EQUAL( i->size(), n+2 );
- Parse_UInt8LVec::iterator j (i->begin());
- Parse_UInt8LVec::iterator je (i->end());
- for (unsigned m (0); m<n+2; ++m, ++j) {
- BOOST_CHECK( j!=je );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(*j), 16*n+m+1 );
- }
- BOOST_CHECK( j==je );
- ++i;
- }
- BOOST_CHECK( i==e );
-
- BOOST_CHECK_EQUAL( l.size(), 3u );
- BOOST_CHECK_EQUAL( l.bytes(), 13u );
- BOOST_CHECK( !l.empty() );
-}
-
-BOOST_AUTO_UNIT_TEST(parse_ListS_wrapper)
-{
- typedef std::vector<unsigned char> Container;
- typedef Container::iterator iterator;
- typedef Parse_LVec<Parse_UInt8<>,Parse_UInt8<>,iterator> Parse_UInt8LVec;
- typedef Parse_ListS<Parse_UInt8LVec, Sentinel_EmptyArray<Parse_UInt8LVec>,iterator> Parse_UInt8LVecListS;
- typedef Parse_UInt8LVecListS::wrapper<Container>::t Parse_UInt8LVecListSWrap;
-
- using namespace boost::assign;
-
- Container data;
- data +=
- 0x02, 0x01, 0x02,
- 0x03, 0x11, 0x12, 0x13,
- 0x04, 0x21, 0x22, 0x23, 0x24,
- 0x00;
-
- Parse_UInt8LVecListS l (data.begin());
- Parse_UInt8LVecListSWrap w (l,data);
-
- BOOST_CHECK_EQUAL( w.size(), 3u );
- BOOST_CHECK ( !w.empty() );
- BOOST_CHECK ( w.begin() != w.end() );
- BOOST_CHECK ( w.range() == std::make_pair(w.begin(), w.end()) );
-
-#if 0
- unsigned char newdata[] = { 0x01, 0x00 };
-
- w.insert(w.begin(),Parse_UInt8LVec::rebind<unsigned char*>::parser(newdata));
- BOOST_CHECK_EQUAL( w.size(), 4u );
- BOOST_CHECK_EQUAL( w.begin()->size(), 1u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>((*w.begin())[0]), 0x00u );
-#endif
-}
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
// Definition of non-inline template funPacketRegistry.ons
-//#include "ParseVec.ih"
+#include "ParseVec.ih"
// Custom includes
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
-template <class Parser, class SizeParser, class Container>
-template <class Value>
-prefix_ void
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::insert(iterator pos,
- Value const & t)
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_Vector<ElementParser,Sizer>
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::init()
+ const
+{
+ sizer_.init(i(),state());
+ iterator i (begin());
+ iterator const e (end());
+ for (; i!=e; ++i)
+ i->init();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_Vector_Container<ElementParser,Sizer>
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::init()
+ const
+{
+ iterator i (begin());
+ iterator const e (end());
+ for (; i!=e; ++i)
+ i->init();
+}
+
+// Mutators
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::iterator
+senf::Parse_Vector_Container<ElementParser,Sizer>::shift(iterator pos, size_type n)
{
- size_type ix(pos.raw()-container_.begin());
- shift(pos);
- Parser(container_.begin()+ix).value(t);
+ size_type ix (std::distance(data().begin(),pos.raw()));
+ data().insert(pos.raw(),n*ElementParser::fixed_bytes,0);
+ setSize(size()+n);
+ return iterator(boost::next(data().begin(),ix),state());
}
-template <class Parser, class SizeParser, class Container>
+template <class ElementParser, class Sizer>
template <class Value>
-prefix_ void
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::insert(iterator pos,
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::insert(iterator pos,
size_type n,
Value const & t)
{
- size_type ix(pos.raw()-container_.begin());
- shift(pos,n);
- typename Container::iterator j (container_.begin()+ix);
- for (; n; --n, j+=Parser::bytes())
- Parser(j).value(t);
+ for (iterator j (shift(pos,n)); n; --n, ++j)
+ *j << t;
+}
+
+template <class ElementParser, class Sizer>
+template <class ForwardIterator>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::
+insert(iterator pos, ForwardIterator f, ForwardIterator l,
+ typename boost::disable_if< boost::is_convertible<ForwardIterator,size_type> >::type *)
+{
+ for (iterator j (shift(pos,std::distance(f,l))); f!=l; ++f,++j)
+ *j << *f;
}
-template <class Parser, class SizeParser, class Container>
-template <class InputIterator>
-prefix_ void
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::insert(iterator pos,
- InputIterator f,
- InputIterator l)
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::resize(size_type n)
+{
+ if (size()>=n)
+ erase(boost::next(begin(),n),end());
+ else
+ push_back_space(n-size());
+}
+
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::resize(size_type n, Value value)
{
- /** \todo This might be horribly inefficient ... we need to
- specialize for random_access and forward iterators, where we
- can count the distance */
-
- size_type ix(pos.raw()-container_.begin());
- for (;f!=l;++f) {
- insert(container_.begin()+ix,*f);
- ix += Parser::bytes();
- }
+ if (size()>=n)
+ erase(boost::next(begin(),n),end());
+ else
+ push_back(value,n-size());
}
///////////////////////////////ct.e////////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
// Definition of inline template functions
-//#include "ParseVec.ih"
+#include "ParseVec.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::
-Parse_Vector(SizeParser const & size)
- : size_(size)
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_Vector<ElementParser,Sizer>
+
+template <class ElementParser, class Sizer>
+prefix_ senf::Parse_Vector<ElementParser,Sizer>::Parse_Vector(data_iterator i, state_type s)
+ : PacketParserBase(i,s), sizer_()
{}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::
-Parse_Vector(size_parser const & size, Iterator const & i)
- : ParserBase<Iterator,IPacket>(i), size_(size)
+template <class ElementParser, class Sizer>
+prefix_ senf::Parse_Vector<ElementParser,Sizer>::Parse_Vector(Sizer sizer, data_iterator i,
+ state_type s)
+ : PacketParserBase(i,s), sizer_(sizer)
{}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ unsigned senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::bytes()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::size_type
+senf::Parse_Vector<ElementParser,Sizer>::bytes()
const
{
- return Parser::bytes()*size();
+ return size()*ElementParser::fixed_bytes + sizer_.bytes(i(),state());
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ void
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::check(Iterator const & e)
+// Container interface
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::size_type
+senf::Parse_Vector<ElementParser,Sizer>::size()
const
{
- return e-this->i() >= bytes();
+ return sizer_.size(i(),state());
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ void senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::init()
+template <class ElementParser, class Sizer>
+prefix_ bool senf::Parse_Vector<ElementParser,Sizer>::empty()
const
{
- iterator e (end());
- for (iterator i (begin()); i!=e; ++i) i->init();
+ return size()==0;
}
-///////////////////////////////////////////////////////////////////////////
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::iterator
+senf::Parse_Vector<ElementParser,Sizer>::begin()
+ const
+{
+ return iterator(sizer_.begin(i(),state()),state());
+}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ typename senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::size_type
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::size()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::iterator
+senf::Parse_Vector<ElementParser,Sizer>::end()
const
{
- return size_.value();
+ return boost::next(begin(),size());
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_ bool senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::empty()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::value_type
+senf::Parse_Vector<ElementParser,Sizer>::operator[](difference_type i)
const
{
- return size()==0;
+ return begin()[i];
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_
-typename senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::iterator
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::begin()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::value_type
+senf::Parse_Vector<ElementParser,Sizer>::front()
const
{
- return iterator(this->i());
+ return begin()[0];
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_
-typename senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::iterator
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::end()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector<ElementParser,Sizer>::value_type
+senf::Parse_Vector<ElementParser,Sizer>::back()
const
{
- return iterator(this->i()+bytes());
+ return begin()[size()-1];
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_
-typename senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::range_type
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::range()
+// Mutators
+
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::push_back(Value value, size_type n)
const
{
- return std::make_pair(begin(),end());
+ container c (*this);
+ c.push_back(value,n);
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_
-typename senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::range_type
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::value()
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::push_back_space(size_type n)
const
{
- return range();
+ container c (*this);
+ c.push_back_space(n);
}
-template <class Parser, class SizeParser, class Iterator, class IPacket>
-prefix_
-typename senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::value_type
-senf::Parse_Vector<Parser,SizeParser,Iterator,IPacket>::operator[](difference_type i)
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::push_front(Value value, size_type n)
const
{
- return begin()[i];
+ container c (*this);
+ c.push_front(value,n);
+}
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::push_front_space(size_type n)
+ const
+{
+ container c (*this);
+ c.push_front_space(n);
+}
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::resize(size_type n)
+ const
+{
+ container c (*this);
+ c.resize(n);
+}
+
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector<ElementParser,Sizer>::resize(size_type n, Value value)
+ const
+{
+ container c (*this);
+ c.resize(n,value);
}
///////////////////////////////////////////////////////////////////////////
+// senf::SimpleSizeParser<SizeParser,offset>
+
+template <class SizeParser>
+prefix_ typename senf::detail::Parse_VectorN_Sizer<SizeParser>::size_type
+senf::detail::Parse_VectorN_Sizer<SizeParser>::size(iterator i, state_type s)
+ const
+{
+ return SizeParser(i,s).value();
+}
+
+template <class SizeParser>
+prefix_ void senf::detail::Parse_VectorN_Sizer<SizeParser>::size(iterator i, state_type s,
+ size_type v)
+ const
+{
+ SizeParser(i,s).value(v);
+}
+
+template <class SizeParser>
+prefix_ typename senf::detail::Parse_VectorN_Sizer<SizeParser>::iterator
+senf::detail::Parse_VectorN_Sizer<SizeParser>::begin(iterator i, state_type s)
+ const
+{
+ return boost::next(i,SizeParser::fixed_bytes);
+}
+
+template <class SizeParser>
+prefix_ typename senf::detail::Parse_VectorN_Sizer<SizeParser>::size_type
+senf::detail::Parse_VectorN_Sizer<SizeParser>::bytes(iterator i, state_type s)
+ const
+{
+ return SizeParser::fixed_bytes;
+}
+
+template <class SizeParser>
+prefix_ void senf::detail::Parse_VectorN_Sizer<SizeParser>::init(iterator i, state_type s)
+ const
+{}
+
+///////////////////////////////////////////////////////////////////////////
// senf::Parse_Vector_wrapper<Parser,SizeParser,Container>
-template <class Parser, class SizeParser, class Container>
-template <class P, class SP, class I, class IP>
-prefix_ senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::
-Parse_Vector_wrapper(Parse_Vector<P,SP,I,IP> const & vector, Container & container)
- : i_(vector.i()-container.begin()), size_i_(vector.size_.i()-container.begin()),
- container_(container)
+// structors and default members
+
+// hm ... be careful here ! the data() member is called in an incompletely intitialized
+// instance. However, data() only depends on state_ which is initialized before the call. YOU MUST
+// NOT CHANGE THE ORDERING OF THE DATA MEMBERS
+template <class ElementParser, class Sizer>
+prefix_ senf::Parse_Vector_Container<ElementParser,Sizer>::
+Parse_Vector_Container(parser_type const & vector)
+ : sizer_ (vector.sizer_), state_ (vector.state()),
+ i_ (std::distance(data().begin(),vector.i()))
{}
-template <class Parser, class SizeParser, class Container>
-prefix_ typename senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::size_type
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::size()
+// accessors
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::size_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::size()
const
{
- return SizeParser(container_.begin()+size_i_).value();
+ return sizer_.size(i(),state());
}
-template <class Parser, class SizeParser, class Container>
-prefix_ bool senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::empty()
+template <class ElementParser, class Sizer>
+prefix_ bool senf::Parse_Vector_Container<ElementParser,Sizer>::empty()
const
{
return size() == 0;
}
-template <class Parser, class SizeParser, class Container>
-prefix_ typename senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::iterator
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::begin()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::iterator
+senf::Parse_Vector_Container<ElementParser,Sizer>::begin()
const
{
- return iterator(container_.begin() + i_);
+ return iterator(sizer_.begin(i(),state()),state());
}
-template <class Parser, class SizeParser, class Container>
-prefix_ typename senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::iterator
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::end()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::iterator
+senf::Parse_Vector_Container<ElementParser,Sizer>::end()
const
{
- return iterator(container_.begin() + i_ + Parser::bytes()*size());
+ return boost::next(begin(),size());
}
-template <class Parser, class SizeParser, class Container>
-prefix_ typename senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::range_type
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::range()
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::value_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::operator[](difference_type i)
const
{
- return std::make_pair(begin(), end());
+ return begin()[i];
}
-template <class Parser, class SizeParser, class Container>
-prefix_ typename senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::value_type
-senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::operator[](difference_type i)
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::value_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::front()
const
{
- return begin()[i];
+ return begin()[0];
+}
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::value_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::back()
+ const
+{
+ return begin()[size()-1];
+}
+
+// Mutators
+
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::insert(iterator pos,
+ Value const & t)
+{
+ *shift(pos) << t;
+}
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::erase(iterator pos, size_type n)
+{
+ data().erase(pos.raw(),boost::next(pos.raw(),n*ElementParser::fixed_bytes));
+ setSize(size()-n);
+}
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::erase(iterator f, iterator l)
+{
+ erase(f,std::distance(f,l));
+}
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::clear()
+{
+ erase(begin(),end());
+}
+
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::push_back(Value value,
+ size_type n)
+{
+ insert(end(),n,value);
}
-template <class Parser, class SizeParser, class Container>
-prefix_ void senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::shift(iterator pos,
- size_type n)
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::push_back_space(size_type n)
{
- container_.insert(pos.raw(),n*Parser::bytes(),0);
- SizeParser(container_.begin()+size_i_) += n;
+ shift(end(),n);
}
-template <class Parser, class SizeParser, class Container>
-prefix_ void senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::erase(iterator pos,
- size_type n)
+template <class ElementParser, class Sizer>
+template <class Value>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::push_front(Value value,
+ size_type n)
{
- container_.erase(pos.raw(),pos.raw()+n*Parser::bytes());
- SizeParser(container_.begin()+size_i_) -= n;
+ insert(begin(),n,value);
}
-template <class Parser, class SizeParser, class Container>
-prefix_ void senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::erase(iterator f,
- iterator l)
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::push_front_space(size_type n)
{
- erase(f,l-f);
+ shift(begin(),n);
}
-template <class Parser, class SizeParser, class Container>
-prefix_ void senf::Parse_Vector_wrapper<Parser,SizeParser,Container>::clear()
+// Parser interface
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::parser_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::parser()
+ const
+{
+ return parser_type(i(),state());
+}
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::data_iterator
+senf::Parse_Vector_Container<ElementParser,Sizer>::i()
+ const
+{
+ return boost::next(data().begin(),i_);
+}
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::state_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::state()
+ const
+{
+ return state_;
+}
+
+template <class ElementParser, class Sizer>
+prefix_ senf::PacketData &
+senf::Parse_Vector_Container<ElementParser,Sizer>::data()
+ const
+{
+ return *state_;
+}
+
+template <class ElementParser, class Sizer>
+prefix_ typename senf::Parse_Vector_Container<ElementParser,Sizer>::size_type
+senf::Parse_Vector_Container<ElementParser,Sizer>::bytes()
+ const
+{
+ return size()*ElementParser::fixed_bytes + sizer_.bytes(i(),state());
+}
+
+// private members
+
+template <class ElementParser, class Sizer>
+prefix_ void senf::Parse_Vector_Container<ElementParser,Sizer>::setSize(size_type value)
{
- container_.erase(container_.begin()+i_,container_.begin()+i_+size()*Parser::bytes());
- SizeParser(container_.begin()+size_i_) = 0;
+ sizer_.size(i(),state(),value);
}
-///////////////////////////////cti.e///////////////////////////////////////
+/////////////////////////////cti.e///////////////////////////////////////
#undef prefix_
\f
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
#define HH_ParseVec_ 1
// Custom includes
-#include <utility> // for std::pair
#include <boost/iterator/iterator_facade.hpp>
-#include <boost/utility.hpp> // for boost::noncopyable
-#include "ParserBase.hh"
+#include <boost/utility.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits.hpp>
+#include "PacketParser.hh"
#include "ParseArray.hh" // for Parse_Array_iterator
//#include "ParseVec.mpp"
namespace senf {
+ template <class ElementParser, class Sizer> class Parse_Vector_Container;
- template <class Parser, class SizeParser, class Container> class Parse_Vector_wrapper;
-
- template <class Parser, class SizeParser, class Iterator=nil, class IPacket=nil>
- struct Parse_Vector : public ParserBase<Iterator,IPacket>
+ /** \brief
+
+ \todo Make the sizer a private baseclass to profit from the empty-base-class optimization
+ */
+ template <class ElementParser, class Sizer>
+ struct Parse_Vector : public PacketParserBase
{
- typedef typename SizeParser::template rebind<Iterator>::parser size_parser;
-
- ///////////////////////////////////////////////////////////////////////////
- // Parser interface
-
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Vector<Parser,SizeParser,I,P> parser; };
- typedef Iterator byte_iterator;
-
- explicit Parse_Vector(SizeParser const & size);
- Parse_Vector(size_parser const & size, Iterator const & i);
+ Parse_Vector(data_iterator i, state_type s);
+ Parse_Vector(Sizer sizer, data_iterator i, state_type s);
- unsigned bytes() const;
- void check(Iterator const & e) const;
+ size_type bytes() const;
void init() const;
+ static const size_type init_bytes = Sizer::init_bytes;
+
///////////////////////////////////////////////////////////////////////////
// Container interface
- typedef typename Parser::template rebind<Iterator>::parser value_type;
- typedef impl::Parse_Array_iterator<value_type,Iterator> iterator;
- typedef unsigned size_type;
- typedef int difference_type;
- typedef std::pair<iterator,iterator> range_type;
-
- template <class Container>
- struct wrapper { typedef Parse_Vector_wrapper<value_type, size_parser, Container> t; };
+ typedef ElementParser value_type;
+ typedef detail::Parse_Array_iterator<value_type> iterator;
+ typedef iterator const_iterator;
+ typedef Parse_Vector_Container<ElementParser,Sizer> container;
size_type size() const;
bool empty() const;
iterator begin() const;
iterator end() const;
- range_type range() const;
- range_type value() const;
value_type operator[](difference_type i) const;
+ value_type front() const;
+ value_type back() const;
+
+ // Mutators
+
+ // The mutators provided here are those which don't take an iterator argument.
+ // If you need to pass an iterator it is much simpler and cleaner to use the
+ // 'container' wrapper
+
+ template <class Value> void push_back (Value value, size_type n=1) const;
+ void push_back_space (size_type n=1) const;
+ template <class Value> void push_front (Value value, size_type n=1) const;
+ void push_front_space (size_type n=1) const;
+ void resize (size_type n) const;
+ template <class Value> void resize (size_type n, Value value) const;
private:
- size_parser size_;
+ Sizer sizer_;
+
+ friend class Parse_Vector_Container<ElementParser,Sizer>;
+ };
+
+ namespace detail { template <class SizeParser> class Parse_VectorN_Sizer; }
- template <class P, class SP, class C> friend class Parse_Vector_wrapper;
+ template <class ElementParser, class SizeParser>
+ struct Parse_VectorN
+ {
+ typedef Parse_Vector< ElementParser,
+ detail::Parse_VectorN_Sizer<SizeParser> > parser;
};
/** \brief
Holds a reference to the container !
*/
- template <class Parser, class SizeParser, class Container>
- class Parse_Vector_wrapper
- : public boost::noncopyable
+ template <class ElementParser, class Sizer>
+ class Parse_Vector_Container
{
public:
///////////////////////////////////////////////////////////////////////////
// Types
- typedef Container container;
- typedef SizeParser size_parser;
- typedef typename Parser::byte_iterator byte_iterator;
- typedef Parser value_type;
- typedef impl::Parse_Array_iterator<value_type,byte_iterator> iterator;
- typedef unsigned size_type;
- typedef int difference_type;
- typedef std::pair<iterator,iterator> range_type;
+ typedef Parse_Vector<ElementParser,Sizer> parser_type;
+ typedef PacketParserBase::data_iterator data_iterator;
+ typedef PacketParserBase::size_type size_type;
+ typedef PacketParserBase::difference_type difference_type;
+ typedef ElementParser value_type;
+ typedef detail::Parse_Array_iterator<value_type> iterator;
+ typedef iterator const_iterator;
+ typedef PacketParserBase::state_type state_type;
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
- template <class P, class SP, class I, class IP>
- Parse_Vector_wrapper(Parse_Vector<P,SP,I,IP> const & vector, Container & container);
-
// no default constructor
- // no copy
+ // default copy
// default destructor
- // no conversion constructors
+ // conversion constructors
+
+ Parse_Vector_Container(parser_type const & vector);
///@}
///////////////////////////////////////////////////////////////////////////
- ///\name APacketRegistry.essors
+
+ ///\name Accessors
///@{
size_type size() const;
iterator begin() const;
iterator end() const;
- range_type range() const;
value_type operator[](difference_type i) const;
+ value_type front() const;
+ value_type back() const;
///@}
- ///////////////////////////////////////////////////////////////////////////
///\name Mutators
///@{
- void shift(iterator pos, size_type n=1);
+ iterator shift(iterator pos, size_type n=1);
template <class Value>
void insert(iterator pos, Value const & t);
template <class Value>
void insert(iterator pos, size_type n, Value const & t);
- template <class InputIterator>
- void insert(iterator pos, InputIterator f, InputIterator l);
+ template <class ForwardIterator>
+ void insert(iterator pos, ForwardIterator f, ForwardIterator l,
+ typename boost::disable_if< boost::is_convertible<ForwardIterator,size_type> >::type * = 0);
void erase(iterator pos, size_type n=1);
void erase(iterator f, iterator l);
void clear();
+ template <class Value> void push_back (Value value, size_type n=1);
+ void push_back_space (size_type n=1);
+ template <class Value> void push_front (Value value, size_type n=1);
+ void push_front_space (size_type n=1);
+ void resize (size_type n);
+ template <class Value> void resize (size_type n, Value value);
+
+ ///@}
+
+ ///\name Parser interface
+ ///@{
+
+ parser_type parser() const;
+ data_iterator i() const;
+ state_type state() const;
+ PacketData & data() const;
+
+ size_type bytes() const;
+ void init() const;
+
///@}
protected:
private:
+ void setSize(size_type value);
+ Sizer sizer_;
+ state_type state_;
size_type i_;
- size_type size_i_;
- Container & container_;
};
}
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#ifndef IH_ParseListS_
-#define IH_ParseListS_ 1
+/** \file
+ \brief ParseVec internal header */
+
+#ifndef IH_ParseVec_
+#define IH_ParseVec_ 1
// Custom includes
-#include <boost/iterator/iterator_facade.hpp>
///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
+namespace detail {
-namespace impl {
-
- template <class Parser, class Sentinel, class Iterator>
- class Parse_ListS_iterator
- : public boost::iterator_facade< Parse_ListS_iterator<Parser,Sentinel,Iterator>,
- Parser,
- boost::forward_traversal_tag,
- Parser >
+ template <class SizeParser>
+ struct Parse_VectorN_Sizer
{
- public:
- Parse_ListS_iterator();
- explicit Parse_ListS_iterator(Iterator const & i);
-
- Iterator raw() const;
+ typedef PacketParserBase::size_type size_type;
+ typedef PacketParserBase::data_iterator iterator;
+ typedef PacketParserBase::state_type state_type;
- private:
- friend class boost::iterator_core_access;
+ static const size_type init_bytes = SizeParser::fixed_bytes;
- Parser dereference() const;
- bool equal(Parse_ListS_iterator const & other) const;
- void increment();
-
- Iterator i_;
- bool atEnd_;
+ size_type size (iterator i, state_type s) const;
+ void size (iterator i, state_type s, size_type v) const;
+ iterator begin (iterator i, state_type s) const;
+ size_type bytes (iterator i, state_type s) const;
+ void init (iterator i, state_type s) const;
};
}}
-
///////////////////////////////ih.e////////////////////////////////////////
#endif
// Local Variables:
// mode: c++
// fill-column: 100
+// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
// Custom includes
#include "ParseVec.hh"
#include "ParseInt.hh"
+#include "PacketType.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-using namespace senf;
+namespace {
+ struct VoidPacket : public senf::PacketTypeBase
+ {};
+}
-BOOST_AUTO_UNIT_TEST(parseVec_test)
+BOOST_AUTO_UNIT_TEST(parseVec)
{
unsigned char data[] = { 0x03, // size
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, // data
0x20, 0x21, 0x22, 0x23, 0x24, 0x25 };
- typedef unsigned char * iterator;
- typedef Parse_Vector<Parse_UInt16<>,Parse_UInt8<>,iterator> Parse_UInt16Vec;
-
- Parse_UInt8<iterator> sizeParser (data);
- Parse_UInt16Vec v (sizeParser, data+1);
-
- BOOST_CHECK_EQUAL( v[0], 0x1011 );
- BOOST_CHECK_EQUAL( v[2], 0x1415 );
- BOOST_CHECK_EQUAL( v.size(), 3u );
- BOOST_CHECK_EQUAL( v.bytes(), 6u );
- data[0] = 0x06;
- BOOST_CHECK_EQUAL( v.size(), 6u );
- BOOST_CHECK_EQUAL( v.bytes(), 12u );
-
- iterator i (data+1);
- Parse_UInt16Vec::iterator j (v.begin());
- Parse_UInt16Vec::iterator e (v.end());
- for (;j!=e;++j, i+=2)
- BOOST_CHECK_EQUAL( Parse_UInt16<iterator>(i), *j );
- BOOST_CHECK_EQUAL(i, data+13);
-}
+ senf::PacketInterpreterBase::ptr p (senf::PacketInterpreter<VoidPacket>::create(data));
+ typedef senf::Parse_Vector<
+ senf::Parse_UInt16,
+ senf::detail::Parse_VectorN_Sizer<senf::Parse_UInt8>
+ > Parse_UInt16Vec;
-BOOST_AUTO_UNIT_TEST(parseVec_wrapper)
-{
- typedef std::vector<unsigned char> Container;
- typedef Container::iterator iterator;
- typedef Parse_UInt8<iterator> Parse_Size;
- typedef Parse_Vector<Parse_UInt16<>,Parse_Size,iterator> Parse_UInt16Vec;
- typedef Parse_UInt16Vec::wrapper<Container>::t Parse_UInt16VecWrap;
+ {
+ Parse_UInt16Vec v (p->data().begin(), &p->data());
+
+ BOOST_CHECK_EQUAL( v[0], 0x1011 );
+ BOOST_CHECK_EQUAL( v[2], 0x1415 );
+ BOOST_CHECK_EQUAL( v.size(), 3u );
+ BOOST_CHECK_EQUAL( v.bytes(), 7u );
+ BOOST_CHECK( ! v.empty() );
+ p->data()[0] = 0x06;
+ BOOST_CHECK_EQUAL( v.size(), 6u );
+ BOOST_CHECK_EQUAL( v.bytes(), 13u );
+
+ Parse_UInt16Vec::iterator b (v.begin());
+ Parse_UInt16Vec::iterator e (v.end());
+ BOOST_CHECK_EQUAL(std::distance(b,e), Parse_UInt16Vec::difference_type(v.size()));
+ }
- using namespace boost::assign;
+ // Warning: Each of the followingoperations invalidate the parser -> we need to recreate it at
+ // each step
- Container data;
- data +=
- 0x03, // size
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, // data
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25;
+ // And since all these members directly call the corresponding members in the container wrapper,
+ // we don't need to check them again below ...
- Parse_Size sizeParser (data.begin());
- Parse_UInt16Vec v (sizeParser, data.begin()+1);
- Parse_UInt16VecWrap w (v,data);
+ {
+# define v Parse_UInt16Vec(p->data().begin(),&p->data())
+
+ v.push_back(0xf0f1u,2);
+ BOOST_CHECK_EQUAL( v.size(), 8u );
+ BOOST_CHECK_EQUAL( v[7], 0xf0f1u );
+
+ v.push_back_space();
+ BOOST_CHECK_EQUAL( v.size(), 9u );
+ BOOST_CHECK_EQUAL( v[8], 0u );
+
+ v.push_front(0xf3f4u);
+ BOOST_CHECK_EQUAL( v.size(), 10u );
+ BOOST_CHECK_EQUAL( v[0], 0xf3f4u );
+ BOOST_CHECK_EQUAL( v[1], 0x1011u );
+
+ v.push_front_space(2);
+ BOOST_CHECK_EQUAL( v.size(), 12u );
+ BOOST_CHECK_EQUAL( v[0], 0u );
+ BOOST_CHECK_EQUAL( v[1], 0u );
+ BOOST_CHECK_EQUAL( v[2], 0xf3f4u );
+ BOOST_CHECK_EQUAL( p->data().size(), 25u );
+
+ v.resize(4);
+ BOOST_CHECK_EQUAL( v.size(), 4u );
+ BOOST_CHECK_EQUAL( p->data().size(), 9u );
+ BOOST_CHECK_EQUAL( v[3], 0x1011u );
+
+ v.resize(6);
+ BOOST_CHECK_EQUAL( v.size(), 6u );
+ BOOST_CHECK_EQUAL( v[5], 0u );
+
+ v.resize(8,0xffff);
+ BOOST_CHECK_EQUAL( v.size(), 8u );
+ BOOST_CHECK_EQUAL( p->data().size(), 17u );
+ BOOST_CHECK_EQUAL( v[6], 0xffffu );
+
+# undef v
+ }
+}
+
+BOOST_AUTO_UNIT_TEST(parseVec_wrapper)
+{
+ unsigned char data[] = { 0x03, // size
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, // data
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25 };
+ senf::PacketInterpreterBase::ptr p (senf::PacketInterpreter<VoidPacket>::create(data));
+ typedef senf::Parse_Vector<
+ senf::Parse_UInt16,
+ senf::detail::Parse_VectorN_Sizer<senf::Parse_UInt8>
+ > Parse_UInt16Vec;
+ Parse_UInt16Vec v (p->data().begin(), &p->data());
+ Parse_UInt16Vec::container w (v);
BOOST_CHECK_EQUAL( w[0], 0x1011 );
BOOST_CHECK_EQUAL( w[2], 0x1415 );
BOOST_CHECK_EQUAL( w.size(), 3u );
- data[0] = 0x06;
+ p->data()[0] = 0x06;
BOOST_CHECK_EQUAL( w.size(), 6u );
-
- {
- iterator i (data.begin()+1);
- Parse_UInt16VecWrap::iterator j (w.begin());
- Parse_UInt16VecWrap::iterator e (w.end());
- for (;j!=e;++j, i+=2)
- BOOST_CHECK_EQUAL( Parse_UInt16<iterator>(i), *j );
- BOOST_CHECK_EQUAL(data.end()-i, 0);
- }
+ BOOST_CHECK_EQUAL( std::distance(w.begin(),w.end()),
+ Parse_UInt16Vec::difference_type(w.size()) );
w.shift(w.begin()+1);
BOOST_CHECK_EQUAL( w.size(), 7u );
BOOST_CHECK_EQUAL( w.size(), 6u );
{
- iterator i (data.begin()+1);
- Parse_UInt16VecWrap::iterator j (w.begin());
- Parse_UInt16VecWrap::iterator e (w.end());
+ senf::PacketData::iterator i (p->data().begin()+1);
+ Parse_UInt16Vec::iterator j (w.begin());
+ Parse_UInt16Vec::iterator e (w.end());
for (;j!=e;++j, i+=2)
- BOOST_CHECK_EQUAL( Parse_UInt16<iterator>(i), *j );
- BOOST_CHECK_EQUAL(data.end()-i, 0);
+ BOOST_CHECK_EQUAL( senf::Parse_UInt16(i,&p->data()), *j );
+ BOOST_CHECK_EQUAL(p->data().end()-i, 0);
}
w.clear();
BOOST_CHECK_EQUAL( w.size(), 0u );
BOOST_CHECK( w.begin() == w.end() );
- BOOST_CHECK_EQUAL( data.size(), 1u );
-}
+ BOOST_CHECK_EQUAL( p->data().size(), 1u );
-// This really belongs into ParserBase.test.cc but it's simpler here
-BOOST_AUTO_UNIT_TEST(parserTraits_test)
-{
- // Really, this could be checked by BOOST_STATIC_ASSERT since
- // it's compile-time ...
- BOOST_CHECK( Parser_traits< Parse_UInt32<> >::fixed_size );
- BOOST_CHECK( (! Parser_traits< Parse_Vector< Parse_UInt16<>,Parse_UInt16<> > >::fixed_size) );
+ BOOST_CHECK_EQUAL( w.parser().size(), 0u );
}
///////////////////////////////cc.e////////////////////////////////////////
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
-// comment-column: 40
// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of inline template functions
-
-#include "ParserBase.ih"
-
-// Custom includes
-
-#define prefix_ inline
-///////////////////////////////cti.p///////////////////////////////////////
-
-template <class Iterator, class IPacket>
-prefix_ Iterator senf::ParserBase<Iterator,IPacket>::i()
- const
-{
- return static_cast<IPacket const *>(this)->begin();
-}
-
-template <class Iterator>
-prefix_ senf::ParserBase<Iterator,senf::nil>::ParserBase(Iterator const & i)
- : i_(i)
-{}
-
-template <class Iterator>
-prefix_ Iterator senf::ParserBase<Iterator,senf::nil>::i()
- const
-{
- return i_;
-}
-
-template <class Parser, class Iterator>
-prefix_ bool senf::impl::check(Iterator const & b, Iterator const & e,
- impl::ParserBase *)
-{
- return impl::ParserCheck<Parser,Parser_traits<Parser>::fixed_size>::check(b,e);
-}
-
-template <class Parser, class Iterator>
-prefix_ bool senf::impl::check(Iterator const & b, Iterator const & e,
- void *)
-{
- return Parser::check(b,e);
-}
-
-template <class Parser, class Iterator>
-prefix_ bool senf::check(Iterator const & b, Iterator const & e)
-{
- return impl::check<Parser,Iterator>(b,e,static_cast<Parser*>(0));
-}
-
-template <class Parser>
-prefix_ unsigned senf::impl::min_bytes(impl::ParserBase *)
-{
- return impl::ParserMinBytes<Parser,Parser_traits<Parser>::fixed_size>::bytes();
-}
-
-template <class Parser>
-prefix_ unsigned senf::impl::min_bytes(void *)
-{
- return 0;
-}
-
-template <class Parser>
-prefix_ unsigned senf::min_bytes()
-{
- return impl::min_bytes<Parser>(static_cast<Parser*>(0));
-}
-
-///////////////////////////////cti.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-/** \file
- \brief Parser framework
- */
-
-#ifndef HH_ParserBase_
-#define HH_ParserBase_ 1
-
-// Custom includes
-#include <utility>
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/type_traits/is_member_function_pointer.hpp>
-
-#include "ParserBase.ih"
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-
-
- namespace impl { struct ParserBase; }
-
- struct nil
- : public boost::iterator_facade<nil,char,boost::random_access_traversal_tag>
- {
- // Theese are declared to make nil a valid iterator. All
- // access to an instance of this iterator however is invalid
- // (these members are not implemented only declared)
- char & dereference() const;
- bool equal(nil other) const;
- void increment();
- void decrement();
- void advance(int n);
- int distance_to(nil other) const;
- };
-
- /** \brief Parser framework
-
- This class is the baseclass for all parser classes of the
- parser framework. The parser framework is used to interpret
- byte-oriented data from arbitrary random access iterators. The
- framework is hierarchical in the sense, that parsers can be
- arbitrarily nested.
-
- All parser framework classes are as lightweight as
- possible. Most parser classes only have a single iterator as
- data member and (depending on the container) therefore have
- the same size as a single pointer. Parsers are therefore
- conceptually and in essence simply pointers decorated with
- type information.
-
- It is very important for parser classes to be lightweight and
- to have only simple constructors since parsers are passed
- around by value. Parser instances most of the time are
- temporaries. However, since they are only 'decorated'
- pointers, this should not have any performance impact.
-
- To implement a new parser, write a template implementing the
- following members:
-
- \code
- template <class Iterator=nil, class IPacket=nil>
- struct Parser_Example
- : protected senf::ParserBase<Iterator,IPacket>
- {
- // fixed interface of all parser classes
-
- template <class I=nil, class P=nil>
- struct rebind { typedef Parse_Example<I,P> parser; }
- typedef Iterator byte_iterator;
-
- Parse_Example() {}
- Parse_Example(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- [static] unsigned bytes()
- {
- // return the size of the parsed header. This
- // method must be declared static if the size is
- // constant, otherwise it must be a non-static
- // member
- return 14;
- }
-
- static bool check(Iterator const & begin, Iterator const & end)
- {
- BOOST_ASSERT( end>=begin );
- // return true, if the data in the range [begin,end)
- // can be safely interpreted by the parser without
- // causing invalid memory access. This means,
- // check, whether the data is truncated
- return static_cast<unsigned>(end-begin) >= bytes();
- }
-
- // optional, only needed if bytes() is non-static
- static unsigned min_bytes()
- {
- // return the minimum size of the header. This
- // is the amount of space needed to allocate
- // an otherwise empty packet
- return 10;
- }
-
- // optional
- void init()
- {
- // initialize the packet if necessary
- }
-
- // optional
- void init(Iterator b, Iterator e)
- {
- // initialize the packet with given payload
- }
-
- // example methods to parse fields
-
- typedef Parse_UInt16 < Iterator > Parse_Field1;
- typedef Parse_Array < 3, Parse_UInt32<>, Iterator > Parser_Field2
-
- Parse_Field1 field1() const { return Parse_Field1 (this->i()); }
- Parse_Field2 field2() const { return Parse_Field2 (this->i()+2); }
- };
- \endcode
-
- Every parser must have some mandatory fixed members which are:
-
- - struct rebind: This structure allows the parser to be
- converted to a parser of the same type but with a different
- iterator. Parser may have more than the two standard
- template parameters. These parameters must then be added in
- front of the standard parameters. The rebind structure must
- however always have only two parameters. Additional
- parameters must be provided from the outside template
-
- - byte_iterator: A typedef for the Iterator class used
-
- - Non Iterator constructor: This constructor is only used when
- the parser is inherited into a Packet class.
-
- - Iterator constructor: This constructor must call the
- corresponding ParserBase constructor.
-
- - unsigned bytes() member: This member must return the number
- of bytes the parser interprets. This will be the size of the
- implemented header. If the header has a fixed size, this
- member must be static, if it is dynamic the member must be
- non-static
-
- - static bool check(Iterator b, Iterator e) member: This
- method must return true \e only if the range [b,e) contains
- a \e complete packet, that is, e-b >= bytes(). However, the
- call to bytes() might involve accessing data bytes which
- might not exist. The bytes() call cannot check this (it has
- no access to the \e end of the valid range). To keep the
- performance up, the validity check is performed once. The
- parser has to ensure, that validity is maintained even when
- changing the values. Validity in this context does not
- imply, that the packet is semantically correct, it only
- implies, that the packet can be parsed without risking
- invalid memory access.
-
- - The min_bytes() member is optional. It is only used, if the
- Parser implements a non-fixed-size Packet, that is, if the
- bytes() member is non-static. In this case, min_bytes() has
- to be implemented and must return the amount of space
- necessary to construct an empty instance. The construction
- will proceed by first allocating the necessary space
- somewhere, initializing this space with all zeros. Then a
- Parser instance is created at that space and the Parsers
- init() method is called.
-
- - The init() member is optional. If all-zero initialization of
- a new Packet is enough, this member can be
- skipped. Otherwise, the init() member can assume to have
- access to a min_buytes() sized area which is all-zero
- initialized.
-
- - The init(Packet::ptr payload) member is optional. By default
- it just calls the init() member. Here, special
- initialization regarding the payload may be done. As for
- min_bytes(Packet::ptr), the argument type is allowed to be
- templatized or may be a specific packet ptr thereby
- restricting the permissible payload packet types.
-
- - The parser then contains any additional methods to parse the
- header constituents.
-
- ParserBase provides the parser classes with access to the
- packet iterator. This class is templatized on the Iterator
- type and an optional baseclass type.
-
- If the baseclass is given, it is used to access the iterator
- directly using 'begin'. If it is not given, the instance has
- to be constructed with an iterator.
-
- This implementation ensures, that a parser can either be
- inherited into a Packet class or be used as a temporary.
- */
- template <class Iterator, class IPacket=nil>
- class ParserBase : public impl::ParserBase
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- ///\name Structors and default members
- ///@{
-
- // default default constructor
- // default copy constructor
- // default copy assignment
- // default destructor
- // no conversion constructors
-
- ///@}
- ///////////////////////////////////////////////////////////////////////////
-
- Iterator i() const;
- static void init() {};
-
- private:
-
- };
-
- template <class Iterator>
- class ParserBase<Iterator,nil> : public impl::ParserBase
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- ///\name Structors and default members
- ///@{
-
- explicit ParserBase(Iterator const & i);
-
- // no default constructor
- // default copy constructor
- // default copy assignment
- // default destructor
- // no conversion constructors
-
- ///@}
- ///////////////////////////////////////////////////////////////////////////
-
- Iterator i() const;
- static void init() {}
- template <class SomePacket>
- static void init(typename SomePacket::ptr) {}
-
- private:
-
- Iterator i_;
- };
-
- /** \brief Addtiional Parser information
-
- Parser_traits provides abstract information about an unknown
- parser. Besides the information already available within the
- Parser it provides an additional 'fixed_sized' member which is
- true if and only if the Parser has a static bytes() member.
- */
- template <class Parser>
- struct Parser_traits {
- typedef Parser parser;
- typedef typename Parser::byte_iterator byte_iterator;
- static const bool fixed_size = impl::Parser_traits_fixed_size<Parser>::fixed_size;
-
- template <class I=nil, class P=nil>
- struct rebind {
- typedef typename Parser::template rebind<I,P>::parser parser;
- };
- };
-
- template <class Parser, class Iterator>
- bool check(Iterator const & b, Iterator const & e);
-
- template <class Parser>
- unsigned min_bytes();
-
-}
-
-///////////////////////////////hh.e////////////////////////////////////////
-//#include "ParserBase.cci"
-//#include "ParserBase.ct"
-#include "ParserBase.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef IH_ParserBase_
-#define IH_ParserBase_ 1
-
-// Custom includes
-
-///////////////////////////////ih.p////////////////////////////////////////
-
-namespace senf {
-
-namespace impl {
-
- struct ParserBase {};
-
- template <unsigned N>
- struct Parser_traits_sentinel
- { int v[N]; };
-
- template <class Parser>
- struct Parser_traits_fixed_size {
- // This differentiates between bytes being a static or
- // non-static member of Parser ...
- static const bool fixed_size = sizeof(
- Parser_traits_fixed_size_check(&Parser::bytes))-sizeof(Parser_traits_sentinel<1>);
- };
-
- template <class R>
- Parser_traits_sentinel<2> Parser_traits_fixed_size_check(R (*)());
-
- template <class R,class T>
- Parser_traits_sentinel<1> Parser_traits_fixed_size_check(R (T::*)() const);
-
- template <class Parser, class Iterator>
- bool check(Iterator const & b, Iterator const & e, ParserBase *);
-
- template <class Parser, class Iterator>
- bool check(Iterator const & b, Iterator const & e, void *);
-
- template <class Parser, bool Fixed>
- struct ParserCheck {
- template <class Iterator>
- static unsigned check(Iterator const & b, Iterator const & e)
- { return Parser::check(b,e); }
- };
-
- template <class Parser>
- struct ParserCheck<Parser,true> {
- template <class Iterator>
- static unsigned check(Iterator const & b, Iterator const & e)
- { return unsigned(e-b) >= Parser::bytes(); }
- };
-
- template <class Parser>
- unsigned min_bytes(ParserBase *);
-
- template <class Parser>
- unsigned min_bytes(void *);
-
- template <class Parser, bool Fixed>
- struct ParserMinBytes {
- static unsigned bytes() { return Parser::min_bytes(); }
- };
-
- template <class Parser>
- struct ParserMinBytes<Parser,true> {
- static unsigned bytes() { return Parser::bytes(); }
- };
-
-}}
-
-///////////////////////////////ih.e////////////////////////////////////////
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Unit tests
-
-//#include "ParserBase.test.hh"
-//#include "ParserBase.test.ih"
-
-// Custom includes
-#include "ParserBase.hh"
-#include "Packet.hh"
-#include <boost/static_assert.hpp>
-
-#include <boost/test/auto_unit_test.hpp>
-#include <boost/test/test_tools.hpp>
-
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-// The non-inherited Version is extensively tested in PaseInt.test.hh
-
-BOOST_AUTO_UNIT_TEST(parserBase_inherited)
-{
- /** \todo Implement */
-}
-
-namespace {
-
- template <class Iterator=senf::nil, class IPacket=senf::nil>
- struct Parse_Test : public senf::ParserBase<Iterator,IPacket>
- {
- template <class I=senf::nil, class P=senf::nil>
- struct rebind { typedef Parse_Test<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_Test() {}
- Parse_Test(Iterator const & i) : senf::ParserBase<Iterator,IPacket>(i) {}
-
- static unsigned bytes() { return 14; }
-
- ///////////////////////////////////////////////////////////////////////////
-
- };
-
- template <class Iterator=senf::nil, class IPacket=senf::nil>
- struct Parse_Test2 : public senf::ParserBase<Iterator,IPacket>
- {
- template <class I=senf::nil, class P=senf::nil>
- struct rebind { typedef Parse_Test<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_Test2() {}
- Parse_Test2(Iterator const & i) : senf::ParserBase<Iterator,IPacket>(i) {}
-
- unsigned bytes() const { return 14; }
- static unsigned check(Iterator a, Iterator b)
- { return true; }
- static unsigned min_bytes() { return 10; }
-
- ///////////////////////////////////////////////////////////////////////////
-
- };
-
-}
-
-BOOST_AUTO_UNIT_TEST(parserBase_construction)
-{
- BOOST_STATIC_ASSERT( senf::Parser_traits< Parse_Test<> >::fixed_size );
- BOOST_STATIC_ASSERT( ! senf::Parser_traits< Parse_Test2<> >::fixed_size );
-
- BOOST_CHECK_EQUAL( senf::min_bytes< Parse_Test<int> >(), 14u );
- BOOST_CHECK( senf::check< Parse_Test<int> >(0,14) );
- BOOST_CHECK( ! senf::check< Parse_Test<int> >(2,15) );
-
- BOOST_CHECK_EQUAL( senf::min_bytes< Parse_Test2<int> >(), 10u );
- BOOST_CHECK( senf::check< Parse_Test2<int> >(2,13) );
- BOOST_CHECK( senf::check< Parse_Test2<int> >(2,12) );
-}
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of non-inline non-template functions
-
-#include "RTCPPacket.hh"
-//#include "RTCPPacket.ih"
-
-// Custom includes
-
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-
-prefix_ void senf::RTCPPacket::v_nextInterpreter()
- const
-{
- registerInterpreter<DataPacket>(begin()+bytes(),end());
-}
-
-prefix_ void senf::RTCPPacket::v_finalize()
-{}
-
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of inline template functions
-
-//#include "RTCPPacket.ih"
-
-// Custom includes
-
-#define prefix_ inline
-///////////////////////////////cti.p///////////////////////////////////////
-
-template <class Arg>
-prefix_ senf::RTCPPacket::RTCPPacket(Arg const & arg)
- : Packet(arg)
-{}
-
-///////////////////////////////cti.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 of the License, or
-// (at your option) any later version.b
-//
-// 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef HH_RTCPPacket_
-#define HH_RTCPPacket_ 1
-
-// Custom includes
-#include "Packets/Packet.hh"
-#include "Packets/ParseInt.hh"
-#include "Packets/ParseArray.hh"
-#include "Packets/ParseListS.hh"
-#include "Packets/ParseVec.hh"
-#include "Packets/PacketRegistry.hh"
-
-//#include "RTCPPacket.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-
-
- template <class I=nil,class P=nil> struct Parse_RTCP_RR;
- template <class I=nil,class P=nil> struct Parse_RTCP_SR;
- template <class I=nil,class P=nil> struct Parse_RTCP_SDES;
- template <class I=nil,class P=nil> struct Parse_RTCP_BYE;
- template <class I=nil,class P=nil> struct Parse_RTCP_APP;
-
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTCP : public ParserBase<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP() {}
- Parse_RTCP(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UIntField < 0, 2, Iterator > Parse_Version;
- typedef Parse_Flag < 2, Iterator > Parse_P;
- typedef Parse_UIntField < 3, 8, Iterator > Parse_Count;
- typedef Parse_UInt8 < Iterator > Parse_PT;
- typedef Parse_UInt16 < Iterator > Parse_Length;
-
- typedef Parse_RTCP_RR < Iterator > Parse_RTCP_RR;
- typedef Parse_RTCP_SR < Iterator > Parse_RTCP_SR;
- typedef Parse_RTCP_SDES < Iterator > Parse_RTCP_SDES;
- typedef Parse_RTCP_BYE < Iterator > Parse_RTCP_BYE;
- typedef Parse_RTCP_APP < Iterator > Parse_RTCP_APP;
-
- Parse_Version version() const { return Parse_Version (this->i() ); }
- Parse_P padding() const { return Parse_P (this->i() ); }
- Parse_Count count() const { return Parse_Count (this->i() ); }
- Parse_PT payloadType() const { return Parse_PT (this->i() + 1 ); }
- Parse_Length length() const { return Parse_Length (this->i() + 2 ); }
-
- Parse_RTCP_RR rr() { return Parse_RTCP_RR (this->i() ); }
- Parse_RTCP_SR sr() { return Parse_RTCP_SR (this->i() ); }
- Parse_RTCP_SDES sdes() { return Parse_RTCP_SDES (this->i() ); }
- Parse_RTCP_BYE bye() { return Parse_RTCP_BYE (this->i() ); }
- Parse_RTCP_APP app() { return Parse_RTCP_APP (this->i() ); }
-
- ///////////////////////////////////////////////////////////////////////////
-
- unsigned int bytes() const { return 32 + (4 * length()); }
- static bool check(Iterator const & b, Iterator const & e)
- { return e-b >= 4 and unsigned(e-b) >= Parse_RTCP<Iterator>(b).bytes(); }
-
- };
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTCP_RB : public ParserBase<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_RB<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_RB() {}
- Parse_RTCP_RB(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_Array < 3, Parse_UInt8<>, Iterator > Parse_24bit;
-
- Parse_32bit ssrc() const { return Parse_32bit(this->i() ); }
- Parse_8bit fragLost() const { return Parse_8bit(this->i()+4 ); }
- Parse_24bit cnpl() const { return Parse_24bit(this->i()+5 ); }
- Parse_32bit ehsnr() const { return Parse_32bit(this->i()+8 ); }
- Parse_32bit LSR() const { return Parse_32bit(this->i()+12); }
- Parse_32bit DLSR() const { return Parse_32bit(this->i()+16); }
-
- ///////////////////////////////////////////////////////////////////////////
-
- static unsigned int bytes() { return 20; }
-
- };
-
- template <class Iterator, class IPacket>
- struct Parse_RTCP_RR : public Parse_RTCP<Iterator, IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_RR<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_RR() {}
- Parse_RTCP_RR(Iterator const & i) : Parse_RTCP<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_Vector < Parse_RTCP_RB<>, typename Parse_RTCP<Iterator,IPacket>::Parse_Count, Iterator > Parse_rbVec;
-
- Parse_32bit ssrc() const { return Parse_32bit(this->i()+ 4 ); }
-
- Parse_32bit ntp_msb() const { return Parse_32bit(this->i()+ 8 ); }
- Parse_32bit ntp_lsb() const { return Parse_32bit(this->i()+ 12 ); }
- Parse_32bit timestamp() const { return Parse_32bit(this->i()+ 16 ); }
- Parse_32bit spcount() const { return Parse_32bit(this->i()+ 20 ); }
- Parse_32bit socount() const { return Parse_32bit(this->i()+ 24 ); }
-
- Parse_rbVec rbVec() const { return Parse_rbVec(this->count(), this->i() + 28 ); }
-
- };
-
- template <class Iterator, class IPacket>
- struct Parse_RTCP_SR : public Parse_RTCP<Iterator, IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_SR<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_SR() {}
- Parse_RTCP_SR(Iterator const & i) : Parse_RTCP<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_Vector < Parse_RTCP_RB<>, typename Parse_RTCP<Iterator,IPacket>::Parse_Count, Iterator > Parse_rbVec;
-
- Parse_32bit ssrc() const { return Parse_32bit(this->i()+ 4 ); }
- Parse_rbVec rbVec() const { return Parse_rbVec(this->count(), this->i() + 8 ); }
-
- };
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTCP_item : public Parse_RTCP<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_item<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_item() {}
- Parse_RTCP_item(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_Vector < Parse_UInt8<>, Parse_UInt8<>, Iterator > Parse_desc;
-
- Parse_8bit typeField() const { return Parse_8bit(this->i() ); }
- Parse_8bit length() const { return Parse_8bit(this->i()+1 ); }
- Parse_desc desc() const { return Parse_desc(this->length(), this->i()+2 ); }
-
-
-
- };
-
- template <class List>
- struct Sentinel_EmptyList {
- static bool check(List a) { return a.empty(); }
- };
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTCP_chunk : public Parse_RTCP<Iterator, IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_chunk<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_chunk() {}
- Parse_RTCP_chunk(Iterator const & i) : Parse_RTCP<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_ListS < Parse_RTCP_item<>, Sentinel_EmptyList<Parse_RTCP_item<> >, Iterator, IPacket> Parse_itemList;
-
- Parse_32bit ssrc() const { return Parse_32bit(this->i() ); }
- Parse_itemList itemList() const { return Parse_itemList(this->i() + 4 ); }
-
- };
-
-
- template <class Iterator, class IPacket>
- struct Parse_RTCP_SDES : public Parse_RTCP<Iterator, IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_SDES<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_SDES() {}
- Parse_RTCP_SDES(Iterator const & i) : Parse_RTCP<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_Vector < Parse_RTCP_chunk<>, typename Parse_RTCP<Iterator,IPacket>::Parse_Count, Iterator > Parse_chunkVec;
-
- Parse_chunkVec chunkVec() const { return Parse_chunkVec(this->count(), this->i()+4 ); }
-
- };
-
- template <class Iterator, class IPacket>
- struct Parse_RTCP_BYE : public Parse_RTCP<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_BYE<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_BYE() {}
- Parse_RTCP_BYE(Iterator const & i) : Parse_RTCP<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_Vector < Parse_UInt32<>, typename Parse_RTCP<Iterator,IPacket>::Parse_Count, Iterator > Parse_ssrcVec;
-
- Parse_ssrcVec ssrcVec() const { return Parse_ssrcVec(this->count(), this->i()+4 ); }
-
- };
-
-
- template <class Iterator, class IPacket>
- struct Parse_RTCP_APP : public Parse_RTCP<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTCP_APP<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTCP_APP() {}
- Parse_RTCP_APP(Iterator const & i) : Parse_RTCP<Iterator,IPacket>(i) {}
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_Vector < Parse_UInt32<>, typename Parse_RTCP<Iterator,IPacket>::Parse_Length, Iterator > Parse_dataVec;
-
- Parse_32bit ssrc() const { return Parse_32bit(this->i()+4); }
- Parse_32bit name() const { return Parse_32bit(this->i()+8); }
-// this->length()-3
- Parse_dataVec appData() const { return Parse_dataVec(this->length(), this->i()+12 ); }
-
- };
-
-
- class RTCPPacket
- : public Packet,
- public Parse_RTCP<Packet::iterator, RTCPPacket>
- {
- using Packet::registerInterpreter;
-
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<RTCPPacket>::ptr ptr;
-
- private:
- template <class Arg>
- RTCPPacket(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
-
- friend class Packet;
- };
-
-}
-
-
-///////////////////////////////hh.e////////////////////////////////////////
-//#include "RTCPPacket.cci"
-//#include "RTCPPacket.ct"
-#include "RTCPPacket.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Unit tests
-
-//#include "RTCPPacket.test.hh"
-//#include "RTCPPacket.test.ih"
-
-// Custom includes
-#include "RTCPPacket.hh"
-
-#include <boost/test/auto_unit_test.hpp>
-#include <boost/test/test_tools.hpp>
-
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-using namespace senf;
-
-BOOST_AUTO_UNIT_TEST(rtcpPacket_parser)
-{
-
- // RTCP RR (no RB)
- unsigned char data_1[] = {
- 0x80, 0xc8, 0x00, 0x06,
- 0xe5, 0x70, 0xaa, 0x18,
- 0xc7, 0xc2, 0xb2, 0x00,
- 0xc3, 0xd7, 0x0e, 0x96,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x0d, 0xc8
-
- };
-
- typedef unsigned char * iterator_1;
- Parse_RTCP<iterator_1> p_1(data_1);
-
- BOOST_CHECK_EQUAL( p_1.version(), 2u );
- BOOST_CHECK_EQUAL( p_1.padding(), 0 );
- BOOST_CHECK_EQUAL( p_1.count(), 0u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_1.payloadType()), 200u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_1.length()), 0x0006u );
-
- BOOST_CHECK_EQUAL(p_1.rr().ssrc(), 0xe570aa18u );
-
- BOOST_CHECK_EQUAL(p_1.rr().ntp_msb(), 0xc7c2b200u );
- BOOST_CHECK_EQUAL(p_1.rr().ntp_lsb(), 0xc3d70e96u );
- BOOST_CHECK_EQUAL(p_1.rr().timestamp(), 0x00u );
- BOOST_CHECK_EQUAL(p_1.rr().spcount(), 0x01u );
- BOOST_CHECK_EQUAL(p_1.rr().socount(), 0x0dc8u );
-
-
- /// \todo RTCP RR
- unsigned char data_2[] = {
- 0x82, 0xc8, 0x00, 0x06,
- 0xe5, 0x70, 0xaa, 0x18,
- 0xc7, 0xc2, 0xb2, 0x00,
- 0xc3, 0xd7, 0x0e, 0x96,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x0d, 0xc8,
-
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16,
- 0x20, 0x21, 0x22, 0x23,
-
- 0x99, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16,
- 0x20, 0x21, 0x22, 0x23
-
- };
-
- typedef unsigned char * iterator_2;
- Parse_RTCP<iterator_2> p_2(data_2);
-
- BOOST_CHECK_EQUAL( p_2.version(), 2u );
- BOOST_CHECK_EQUAL( p_2.padding(), 0 );
- BOOST_CHECK_EQUAL( p_2.count(), 2u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_2.payloadType()), 200u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_2.length()), 0x0006u );
-
- BOOST_CHECK_EQUAL(p_2.rr().ssrc(), 0xe570aa18u );
-
- BOOST_CHECK_EQUAL(p_2.rr().ntp_msb(), 0xc7c2b200u );
- BOOST_CHECK_EQUAL(p_2.rr().ntp_lsb(), 0xc3d70e96u );
- BOOST_CHECK_EQUAL(p_2.rr().timestamp(), 0x00u );
- BOOST_CHECK_EQUAL(p_2.rr().spcount(), 0x01u );
- BOOST_CHECK_EQUAL(p_2.rr().socount(), 0x0dc8u );
-
- BOOST_CHECK_EQUAL( p_2.rr().rbVec().size(), 0x02u );
-
-
- BOOST_CHECK_EQUAL( p_2.rr().rbVec().begin()->ssrc(), 0x01020304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_2.rr().rbVec().begin()->fragLost()), 0x05u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_2.rr().rbVec().begin()->cnpl()[0]), 0x06u );
- BOOST_CHECK_EQUAL( p_2.rr().rbVec().begin()->ehsnr(), 0x09101112u );
- BOOST_CHECK_EQUAL( p_2.rr().rbVec().begin()->LSR(), 0x13141516u );
- BOOST_CHECK_EQUAL( p_2.rr().rbVec().begin()->DLSR(), 0x20212223u );
-
- typedef unsigned char * iterator;
- typedef Parse_UIntField < 3, 8, iterator > Parse_Count;
- typedef Parse_Vector < Parse_RTCP_RB<>, Parse_Count, iterator > Parse_rbVec;
-
- Parse_rbVec::iterator j_2 (p_2.rr().rbVec().begin());
-
- BOOST_CHECK_EQUAL( j_2->ssrc(), 0x01020304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j_2->fragLost()), 0x05u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j_2->cnpl()[0]), 0x06u );
- BOOST_CHECK_EQUAL( j_2->ehsnr(), 0x09101112u );
- BOOST_CHECK_EQUAL( j_2->LSR(), 0x13141516u );
- BOOST_CHECK_EQUAL( j_2->DLSR(), 0x20212223u );
-
- ++j_2;
-
- BOOST_CHECK_EQUAL( j_2->ssrc(), 0x99020304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j_2->fragLost()), 0x05u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j_2->cnpl()[0]), 0x06u );
- BOOST_CHECK_EQUAL( j_2->ehsnr(), 0x09101112u );
- BOOST_CHECK_EQUAL( j_2->LSR(), 0x13141516u );
- BOOST_CHECK_EQUAL( j_2->DLSR(), 0x20212223u );
-
-
-
-
-
-
- // RTCP SR
- unsigned char data_3[] = {
- 0x82, 0xc9, 0x00, 0x06,
- 0xe5, 0x70, 0xaa, 0x18,
-
- 0x99, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16,
- 0x20, 0x21, 0x22, 0x23,
-
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16,
- 0x20, 0x21, 0x22, 0x23
-
- };
-
- typedef unsigned char * iterator_3;
- Parse_RTCP<iterator_3> p_3(data_3);
-
- BOOST_CHECK_EQUAL( p_3.version(), 2u );
- BOOST_CHECK_EQUAL( p_3.padding(), 0 );
- BOOST_CHECK_EQUAL( p_3.count(), 2u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_3.payloadType()), 201u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_3.length()), 0x0006u );
-
- BOOST_CHECK_EQUAL( p_3.sr().ssrc(), 0xe570aa18u );
- BOOST_CHECK_EQUAL( p_3.sr().rbVec().size(), 0x02u );
-
-
- typedef unsigned char * iterator;
- typedef Parse_UIntField < 3, 8, iterator > Parse_Count;
- typedef Parse_Vector < Parse_RTCP_RB<>, Parse_Count, iterator > Parse_rbVec;
-
- Parse_rbVec::iterator j (p_3.rr().rbVec().begin());
- BOOST_CHECK_EQUAL( j->ssrc(), 0x01020304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j->fragLost()), 0x05u );
- BOOST_CHECK_EQUAL( j->ehsnr(), 0x09101112u );
- BOOST_CHECK_EQUAL( j->LSR(), 0x13141516u );
- BOOST_CHECK_EQUAL( j->DLSR(), 0x20212223u );
-
- ++j;
-
-#if 0
- BOOST_CHECK_EQUAL( j->ssrc(), 0x99020304u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j->fragLost()), 0x05u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(j->cnpl()[0]), 0x06u );
- BOOST_CHECK_EQUAL( j->ehsnr(), 0x09101112u );
- BOOST_CHECK_EQUAL( j->LSR(), 0x13141516u );
- BOOST_CHECK_EQUAL( j->DLSR(), 0x20212223u );
-#endif
-
- /// \todo RTCP SDES
-
- unsigned char data_4[] = {
- 0x81, 0xca, 0x00, 0x04,
- 0xe5, 0x70, 0xaa, 0x18,
- 0x01, 0x09, 0x39, 0x30,
- 0x31, 0x31, 0x33, 0x35,
- 0x37, 0x36, 0x37, 0x00
-
- };
-
- typedef unsigned char * iterator_4;
- Parse_RTCP<iterator_4> p_4(data_4);
-
- BOOST_CHECK_EQUAL( p_4.version(), 2u );
- BOOST_CHECK_EQUAL( p_4.padding(), 0 );
- BOOST_CHECK_EQUAL( p_4.count(), 1u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_4.payloadType()), 202u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_4.length()), 0x0004u );
-
- BOOST_CHECK_EQUAL( p_4.sdes().chunkVec().size(), 0x01u );
-#if 0
- Parse_RTCP_SDES::Parse_itemList::iterator j_4 (p_4.sdes().chunkVec().begin());
-
-/// \todo ask Stefan
-
- // BOOST_CHECK_EQUAL( p_4.sdes().chunkList()[0].ssrc(), 0xe570aa18u);
- // BOOST_CHECK_EQUAL( p_4.sdes().chunkList()[0].itemList().size(), 0x01u);
- // BOOST_CHECK( p_4.sdes().chunkList()[0].itemList().check(data_4+20) );
- // BOOST_CHECK_EQUAL(p.sdes().chunkList()[0].chunkList().size(), 1);
-
-//item
-// typeField(), 0x01u
-// length(), 0x09u
-// desc(), 0x393031313335373637u
-
-#endif
-
-
- // RTCP BYE
- unsigned char data_5[] = {
- 0x82, 0xcb, 0x00, 0x06,
-
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08
-
- };
-
- typedef unsigned char * iterator_5;
- Parse_RTCP<iterator_5> p_5(data_5);
-
- BOOST_CHECK_EQUAL( p_5.version(), 2u );
- BOOST_CHECK_EQUAL( p_5.padding(), 0 );
- BOOST_CHECK_EQUAL( p_5.count(), 2u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_5.payloadType()), 203u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_5.length()), 0x0006u );
-
- BOOST_CHECK_EQUAL( p_5.bye().ssrcVec().size(), 0x02u );
-
- BOOST_CHECK_EQUAL( p_5.bye().ssrcVec()[0], 0x01020304u );
- BOOST_CHECK_EQUAL( p_5.bye().ssrcVec()[1], 0x05060708u );
-
-
- // RTCP APP
- unsigned char data_6[] = {
- 0x82, 0x7b, 0x00, 0x05,
-
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x10, 0x11, 0x12,
- 0x00, 0x00, 0x00, 0x08
-
- };
-
- typedef unsigned char * iterator_6;
- Parse_RTCP<iterator_6> p_6(data_6);
-
- BOOST_CHECK_EQUAL( p_6.version(), 2u );
- BOOST_CHECK_EQUAL( p_6.padding(), 0 );
- BOOST_CHECK_EQUAL( p_6.count(), 2u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_6.payloadType()), 123u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_6.length()), 0x0005u );
-
- BOOST_CHECK_EQUAL( p_6.app().ssrc(), 0x01020304u );
- BOOST_CHECK_EQUAL( p_6.app().name(), 0x05060708u );
-#if 0
- BOOST_CHECK_EQUAL( p_6.app().appData().size(), 2u );
-#endif
- BOOST_CHECK_EQUAL( p_6.app().appData()[0], 0x09101112u );
- BOOST_CHECK_EQUAL( p_6.app().appData()[1], 0x08u );
-
-}
-
-
-BOOST_AUTO_UNIT_TEST(rtcpPacket_packet)
-{
-#if 0
- unsigned char data_1[] = {
- 0x80, 0xc8, 0x00, 0x06,
- 0xe5, 0x70, 0xaa, 0x18,
- 0xc7, 0xc2, 0xb2, 0x00,
- 0xc3, 0xd7, 0x0e, 0x96,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x0d, 0xc8
-
- };
-
- RTCPPacket::ptr p_1 (Packet::create<RTCPPacket>(data_1, data_1+sizeof(data_1)));
-
- BOOST_CHECK_EQUAL( p_1->version(), 2u );
- BOOST_CHECK_EQUAL( p_1->padding(), 0 );
- BOOST_CHECK_EQUAL( p_1->count(), 0u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_1->payloadType()), 200u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p_1->length()), 0x0006u );
-
- BOOST_CHECK_EQUAL(p_1->rr().ssrc(), 0xe570aa18u );
-
- BOOST_CHECK_EQUAL(p_1->rr().ntp_msb(), 0xc7c2b200u );
- BOOST_CHECK_EQUAL(p_1->rr().ntp_lsb(), 0xc3d70e96u );
- BOOST_CHECK_EQUAL(p_1->rr().timestamp(), 0x00u );
- BOOST_CHECK_EQUAL(p_1->rr().spcount(), 0x01u );
- BOOST_CHECK_EQUAL(p_1->rr().socount(), 0x0dc8u );
-#endif
-
-}
-
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Definition of non-inline non-template functions
-
-#include "RTPPacket.hh"
-//#include "RTPPacket.ih"
-
-// Custom includes
-
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-
-prefix_ void senf::RTPPacket::v_nextInterpreter()
- const
-{
-
- if(extension()){
- Packet::registerInterpreter<RTPUnknownExtensionPacket>(begin()+bytes(),end());
- }else{
-
- int paddingOctets = 0;
- if(padding()){
- paddingOctets = paddingOctet();
- }
- registerInterpreter(payloadType(),begin()+bytes(),end()-paddingOctets);
- }
-}
-
-prefix_ void senf::RTPPacket::v_finalize()
-{}
-
-prefix_ void senf::RTPPacket::v_dump(std::ostream & os)
- const
-{
- os << "RTP:\n"
- << " version : " << version() << "\n"
- << " padding : " << padding() << "\n"
- << " extension : " << extension() << "\n"
- << " csrc count : " << csrcCount() << "\n"
- << " marker : " << marker() << "\n"
- << " payload type : " << payloadType() << "\n"
- << " sequence nr : " << seqNumber() << "\n"
- << " timestamp : " << timestamp() << "\n"
- << " ssrc : " << ssrc() << "\n"
- << " csrc list : <not shown>\n";
-}
-
-prefix_ void senf::RTPExtensionBasePacket::v_nextInterpreter()
- const
-{
-
- // We don't want to inherit Parse_RTPExtensionBase to avoid
- // virtual inheritance problems. Since we need the size of the
- // extension, we just allocate ourselves a ExtensionBase parser
-
- Parse_RTPExtensionBase<iterator> p (begin());
- if (!p.check(begin(),end()))
- throw TruncatedPacketException();
-
- int paddingOctets = 0;
- if(get_prev<RTPPacket>()->padding()){
- paddingOctets = get_prev<RTPPacket>()->paddingOctet();
- }
- registerInterpreter(get_prev<RTPPacket>()->payloadType(),begin()+p.bytes(),end()-paddingOctets);
-}
-
-prefix_ void senf::RTPExtensionBasePacket::v_dump(std::ostream & os)
- const
-{
- os << "RTP extension packet:\n"
- << " content not shown\n";
-}
-
-prefix_ void senf::RTPUnknownExtensionPacket::v_finalize()
-{}
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 of the License, or
-// (at your option) any later version.b
-//
-// 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef HH_RTPPacket_
-#define HH_RTPPacket_ 1
-
-// Custom includes
-#include "Packets/Packet.hh"
-#include "Packets/ParseInt.hh"
-#include "Packets/ParseArray.hh"
-#include "Packets/ParseVec.hh"
-#include "Packets/PacketRegistry.hh"
-
-//#include "RTPPacket.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
-
-namespace senf {
-
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTP : public ParserBase<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTP<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTP() {}
- Parse_RTP(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UIntField < 0, 2, Iterator > Parse_Version;
- typedef Parse_Flag < 2, Iterator > Parse_P;
- typedef Parse_Flag < 3, Iterator > Parse_X;
- typedef Parse_UIntField < 4, 8, Iterator > Parse_CC;
- typedef Parse_Flag < 0, Iterator > Parse_M;
- typedef Parse_UIntField < 1, 8, Iterator > Parse_PT;
- typedef Parse_UInt16 < Iterator > Parse_Seq;
- typedef Parse_UInt32 < Iterator > Parse_32bit;
- typedef Parse_Vector < Parse_32bit, Parse_CC, Iterator > Parse_CCVec;
-
- Parse_Version version() const { return Parse_Version (this->i() ); }
- Parse_P padding() const { return Parse_P (this->i() ); }
- Parse_X extension() const { return Parse_X (this->i() ); }
- Parse_CC csrcCount() const { return Parse_CC (this->i() ); }
- Parse_M marker() const { return Parse_M (this->i() + 1 ); }
- Parse_PT payloadType() const { return Parse_PT (this->i() + 1 ); }
- Parse_Seq seqNumber() const { return Parse_Seq (this->i() + 2 ); }
- Parse_32bit timestamp() const { return Parse_32bit (this->i() + 4 ); }
- Parse_32bit ssrc() const { return Parse_32bit (this->i() + 8 ); }
- Parse_CCVec csrcList() const { return Parse_CCVec (csrcCount(), this->i() + 12 ); }
-
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- unsigned int bytes() const { return 12 + ( 4 * csrcCount()); }
- static bool check(Iterator const & b, Iterator const & e)
- { return e-b>= 12 and unsigned(e-b) >= Parse_RTP<Iterator>(b).bytes(); }
-
- };
-
- struct RTPTypes {
- typedef boost::uint16_t key_t;
- };
-
- class RTPPacket
- : public Packet,
- public Parse_RTP<Packet::iterator, RTPPacket>,
- public PacketRegistryMixin<RTPTypes,RTPPacket>
- {
- using Packet::registerInterpreter;
- using PacketRegistryMixin<RTPTypes,RTPPacket>::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<RTPPacket>::ptr ptr;
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt8 < Packet::iterator > Parse_paddingOctet;
-
- Parse_paddingOctet paddingOctet() const {
- return Parse_paddingOctet( end() -1 );
- }
-
- private:
- template <class Arg>
- RTPPacket(Arg const & arg);
-
- virtual void v_nextInterpreter() const;
- virtual void v_finalize();
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
- };
-
-
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTPExtensionBase : public ParserBase<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTPExtensionBase<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTPExtensionBase() {}
- Parse_RTPExtensionBase(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt16 < Iterator > Parse_16bit;
-
- Parse_16bit proDef() const { return Parse_16bit(this->i()); };
- Parse_16bit length() const { return Parse_16bit(this->i()+2); };
-
- unsigned int bytes() const { return 4 + length(); }
- static bool check(Iterator const & b, Iterator const & e)
- { return e-b>=4 && unsigned(e-b) >= Parse_RTPExtensionBase<Iterator>(b).bytes(); }
-
-
- };
-
- class RTPExtensionBasePacket
- : public Packet,
- public PacketRegistryMixin<RTPTypes, RTPExtensionBasePacket>
- {
- using PacketRegistryMixin<RTPTypes,RTPExtensionBasePacket>::registerInterpreter;
- using Packet::registerInterpreter;
- public:
- ///////////////////////////////////////////////////////////////////////////
- typedef ptr_t<RTPExtensionBasePacket>::ptr ptr;
-
- protected:
- template <class Arg>
- RTPExtensionBasePacket(Arg const & arg);
-
- private:
- virtual void v_nextInterpreter() const;
- virtual void v_finalize() = 0;
- virtual void v_dump(std::ostream & os) const;
-
- friend class Packet;
-
- };
-
-
- template <class Iterator=nil, class IPacket=nil>
- struct Parse_RTPUnknownExtension : public Parse_RTPExtensionBase<Iterator,IPacket>
- {
- template <class I, class P=nil>
- struct rebind { typedef Parse_RTPUnknownExtension<I,P> parser; };
- typedef Iterator byte_iterator;
-
- Parse_RTPUnknownExtension() {}
- Parse_RTPUnknownExtension(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
-
- ///////////////////////////////////////////////////////////////////////////
-
- typedef Parse_UInt16 < Iterator > Parse_16bit;
- typedef Parse_UInt8 < Iterator > Parse_8bit;
- typedef Parse_Vector < Parse_8bit, Parse_16bit, Iterator > Parse_ext;
-
- Parse_ext ext() const { return Parse_ext (this->length(), this->i() + 4 ); }
-
- };
-
- class RTPUnknownExtensionPacket
- : public RTPExtensionBasePacket,
- public Parse_RTPUnknownExtension<Packet::iterator, RTPUnknownExtensionPacket>
- {
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
-
- typedef ptr_t<RTPUnknownExtensionPacket>::ptr ptr;
-
- ///////////////////////////////////////////////////////////////////////////
-
- private:
- template <class Arg>
- RTPUnknownExtensionPacket(Arg const & arg);
-
- //virtual void v_nextInterpreter() const;
- virtual void v_finalize();
-
- friend class RTPExtensionBasePacket;
- friend class Packet;
- };
-
-}
-
-
-///////////////////////////////hh.e////////////////////////////////////////
-//#include RTPPacket.cci"
-//#include "RTPPacket.ct"
-#include "RTPPacket.cti"
-#endif
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
-//
-// 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 2 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, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-// Unit tests
-
-//#include "RTPPacket.test.hh"
-//#include "RTPPacket.test.ih"
-
-// Custom includes
-#include "RTPPacket.hh"
-
-#include "Packets/DefaultBundle/EthernetPacket.hh"
-#include "Packets/DefaultBundle/IpV4Packet.hh"
-#include "Packets/DefaultBundle/UDPPacket.hh"
-
-#include <boost/test/auto_unit_test.hpp>
-#include <boost/test/test_tools.hpp>
-
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-using namespace senf;
-
-BOOST_AUTO_UNIT_TEST(rtpPacket_parser)
-{
- unsigned char data[] = { 0x13, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0A, 0x0B, 0x0C,
-
- 0x11, 0x12, 0x13, 0x14, // CSRC 1
- 0x15, 0x16, 0x17, 0x18, // CSRC 2
- 0x19, 0x1A, 0x1B, 0x1C // CSRC 3
-
- };
-
- typedef unsigned char * iterator;
- Parse_RTP<iterator> p(data);
-
- BOOST_CHECK_EQUAL( p.version(), 0x00u );
- BOOST_CHECK_EQUAL( p.padding(), 0 );
- BOOST_CHECK_EQUAL( p.extension(), 1 );
- BOOST_CHECK_EQUAL( p.csrcCount(), 0x03u );
- BOOST_CHECK_EQUAL( p.marker(), 0 );
- BOOST_CHECK_EQUAL( p.payloadType(), 0x02u );
- // the static_cast is to silence gcc-3.3
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p.seqNumber()), 0x0304u );
- BOOST_CHECK_EQUAL( p.timestamp(), 0x05060708u );
- BOOST_CHECK_EQUAL( p.ssrc(), 0x090A0B0Cu );
-
- BOOST_CHECK_EQUAL( p.csrcList()[0], 0x11121314u );
- BOOST_CHECK_EQUAL( p.csrcList()[1], 0x15161718u );
- BOOST_CHECK_EQUAL( p.csrcList()[2], 0x191A1B1Cu );
-
-
-}
-
-
-BOOST_AUTO_UNIT_TEST(rtpPacket_packet)
-{
- unsigned char data[] = { 0x33, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0A, 0x0B, 0x0C,
-
- 0x11, 0x12, 0x13, 0x14, // CSRC 1
- 0x15, 0x16, 0x17, 0x18, // CSRC 2
- 0x19, 0x1A, 0x1B, 0x1C, // CSRC 3
-
- 0x20, 0x21, 0x00, 0x04, // ex
- 0x24, 0x25, 0x26, 0x27, // ex
-
- 0x20, 0x21, 0x08, 0x23, // paylaod
- 0x20, 0x00, 0x00, 0x03 // payload
-
- };
-
- RTPPacket::ptr p (Packet::create<RTPPacket>(data, data+sizeof(data)));
-
- BOOST_CHECK_EQUAL( p->version(), 0x00u );
- BOOST_CHECK_EQUAL( p->padding(), 1 );
- BOOST_CHECK_EQUAL( p->extension(), 1 );
- BOOST_CHECK_EQUAL( p->csrcCount(), 0x03u );
- BOOST_CHECK_EQUAL( p->marker(), 0 );
- BOOST_CHECK_EQUAL( p->payloadType(), 0x02u );
- // the static_cast is to silence gcc-3.3
- BOOST_CHECK_EQUAL( static_cast<unsigned>(p->seqNumber()), 0x0304u );
- BOOST_CHECK_EQUAL( p->timestamp(), 0x05060708u );
- BOOST_CHECK_EQUAL( p->ssrc(), 0x090A0B0Cu );
-
- BOOST_CHECK_EQUAL( p->paddingOctet(), 3 );
-
- BOOST_CHECK_EQUAL( p->csrcList()[0], 0x11121314u );
- BOOST_CHECK_EQUAL( p->csrcList()[1], 0x15161718u );
- BOOST_CHECK_EQUAL( p->csrcList()[2], 0x191A1B1Cu );
-
- BOOST_REQUIRE( p->next() );
- BOOST_CHECK( p->next()->is<RTPUnknownExtensionPacket>() );
-
- RTPUnknownExtensionPacket::ptr v (p->next()->as<RTPUnknownExtensionPacket>());
- BOOST_CHECK_EQUAL( static_cast<unsigned>(v->proDef()), 0x2021u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(v->length()), 0x04u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(v->ext()[0]), 0x24u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(v->ext()[2]), 0x26u );
-
- BOOST_REQUIRE( v->next() );
- DataPacket::ptr d (v->next()->as<DataPacket>());
-
- BOOST_CHECK_EQUAL( d->size(), 5u );
-
-}
-
-
-
-BOOST_AUTO_UNIT_TEST(eth_rtpPacket_packet)
-{
- unsigned char data[] = {
-
- // Ethernet
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // destination MAC
- 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, // source MAC
- 0x08, 0x00, // EtherType: IPv4 0x08
-
- // IPv4
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x11, 0x0B, 0x0C, // EtherType: UDP 0x11
- 0x11, 0x12, 0x13, 0x14,
- 0x15, 0x16, 0x17, 0x18,
-
- // UDP
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
-
- // RTP
- 0x33, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0A, 0x0B, 0x0C,
-
- 0x11, 0x12, 0x13, 0x14, // CSRC 1
- 0x15, 0x16, 0x17, 0x18, // CSRC 2
- 0x19, 0x1A, 0x1B, 0x1C, // CSRC 3
-
- 0x20, 0x21, 0x00, 0x04, // ex
- 0x24, 0x25, 0x26, 0x27, // ex
-
- 0x20, 0x21, 0x08, 0x23, // paylaod
- 0x20, 0x00, 0x00, 0x03 // payload
-
- };
-
- // Ethernet
- EthernetPacket::ptr p (Packet::create<EthernetPacket>(data, data+sizeof(data)));
-
- BOOST_CHECK_EQUAL( p->destination()[3], 0x04 );
- BOOST_CHECK_EQUAL( p->source()[0], 0x07 );
- BOOST_CHECK_EQUAL( p->type(), 0x0800 );
-
- // IP
- BOOST_REQUIRE( p->next() );
- BOOST_CHECK( p->next()->is<IpV4Packet>() );
-
- IpV4Packet::ptr ip (p->next()->as<IpV4Packet>());
-
- BOOST_CHECK_EQUAL( static_cast<unsigned>(ip->protocol()), 0x11u );
-
- // UDP
- BOOST_REQUIRE( ip->next() );
- BOOST_CHECK( ip->next()->is<UDPPacket>() );
-
- UDPPacket::ptr udp (ip->next()->as<UDPPacket>());
-
- BOOST_CHECK_EQUAL( udp->source(), 0x0102 );
- BOOST_CHECK_EQUAL( udp->destination(), 0x0304 );
- BOOST_CHECK_EQUAL( udp->length(), 0x0506 );
- BOOST_CHECK_EQUAL( udp->crc(), 0x0708 );
-
-
- // RTP
- BOOST_REQUIRE( udp->next() );
- BOOST_CHECK( udp->next()->is<DataPacket>() );
-
- RTPPacket::ptr rtp (udp->next()->reinterpret<RTPPacket>());
-
- BOOST_CHECK_EQUAL( rtp->version(), 0x00u );
- BOOST_CHECK_EQUAL( rtp->padding(), 1 );
- BOOST_CHECK_EQUAL( rtp->extension(), 1 );
- BOOST_CHECK_EQUAL( rtp->csrcCount(), 0x03u );
- BOOST_CHECK_EQUAL( rtp->marker(), 0 );
- BOOST_CHECK_EQUAL( rtp->payloadType(), 0x02u );
- // the static_cast is to silence gcc-3.3
- BOOST_CHECK_EQUAL( static_cast<unsigned>(rtp->seqNumber()), 0x0304u );
- BOOST_CHECK_EQUAL( rtp->timestamp(), 0x05060708u );
- BOOST_CHECK_EQUAL( rtp->ssrc(), 0x090A0B0Cu );
-
- BOOST_CHECK_EQUAL( rtp->paddingOctet(), 3 );
-
- BOOST_CHECK_EQUAL( rtp->csrcList()[0], 0x11121314u );
- BOOST_CHECK_EQUAL( rtp->csrcList()[1], 0x15161718u );
- BOOST_CHECK_EQUAL( rtp->csrcList()[2], 0x191A1B1Cu );
-
- BOOST_REQUIRE( rtp->next() );
- BOOST_CHECK( rtp->next()->is<RTPUnknownExtensionPacket>() );
-
- RTPUnknownExtensionPacket::ptr ex (rtp->next()->as<RTPUnknownExtensionPacket>());
- BOOST_CHECK_EQUAL( static_cast<unsigned>(ex->proDef()), 0x2021u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(ex->length()), 0x04u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(ex->ext()[0]), 0x24u );
- BOOST_CHECK_EQUAL( static_cast<unsigned>(ex->ext()[2]), 0x26u );
-
- BOOST_REQUIRE( ex->next() );
- DataPacket::ptr pay (ex->next()->as<DataPacket>());
-
- BOOST_CHECK_EQUAL( pay->size(), 5u );
-
-}
-
-
-
-
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// fill-column: 100
-// c-file-style: "senf"
-// indent-tabs-mode: nil
-// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
-// End:
+++ /dev/null
-# -*- python -*-
-
-Import('env')
-import SENFSCons, glob
-
-###########################################################################
-
-sources = SENFSCons.GlobSources()
-
-SENFSCons.StandardTargets(env)
-
-SENFSCons.Object(env, target = 'RTPBundle', sources=sources,
- LIBS = ['Packets', 'Socket', 'Utils'],
- OBJECTS = ['#/Packets/DefaultBundle/DefaultBundle.o'])
-
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#ifndef HH_docstub_
-#define HH_docstub_ 1
+/** \file
+ \brief main.test public header */
+
+#ifndef HH_main_test_
+#define HH_main_test_ 1
// Custom includes
-//#include "docstub.mpp"
+//#include "main.test.mpp"
///////////////////////////////hh.p////////////////////////////////////////
-namespace boost {
-
- struct noncopyable {};
- template <class Derived> struct totally_ordered {};
- template <class Derived, class Value, class Traversal, class Reference> struct iterator_facade {};
- template <class T> struct intrusive_ptr { T * ptr; };
- template <class T> struct shared_ptr { T * ptr; };
+namespace senf {
+namespace detail {
+namespace packet {
+namespace test {
-}
+ struct TestDriver {
+ template <class T>
+ static typename PacketInterpreter<T>::ptr create(PacketImpl * impl, iterator b, iterator e,
+ PacketInterpreterBase::Append_t)
+ { return PacketInterpreter<T>::create(impl,b,e,PacketInterpreterBase::Append); }
-namespace std {
+ template <class T>
+ static typename PacketInterpreter<T>::ptr create(PacketImpl * impl, iterator b, iterator e,
+ PacketInterpreterBase::Prepend_t)
+ { return PacketInterpreter<T>::create(impl,b,e,PacketInterpreterBase::Prepend); }
- struct exception {};
- template <class T> struct vector { T * elements; };
- template <class T> struct list { T * elements; };
+ static PacketImpl * impl(PacketInterpreterBase::ptr p)
+ { return &p->impl(); }
+ };
-}
+}}}}
///////////////////////////////hh.e////////////////////////////////////////
-//#include "docstub.cci"
-//#include "docstub.ct"
-//#include "docstub.cti"
+//#include "main.test.cci"
+//#include "main.test.ct"
+//#include "main.test.cti"
#endif
\f
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
std::string buffer_;
};
+ enum NoThrow_t { nothrow };
+
}
///////////////////////////////hh.e////////////////////////////////////////
This type trait returns \c true, if \a RandomAccessIterator is an iterator into a contiguous
storage area which may be written to. If this is the case, some algorithms may be optimized
by directly modifying the underlying storage instead of relying on the STL interface.
+
+ \code
+ // Generic algorithm
+ template <class Iterator>
+ void do(Iterator i, boost::false_type)
+ {
+ // Access the iterator 'i' via the standard STL interface
+ }
+
+ template<class Iterator>
+ void do(Iterator i, boost::true_type)
+ {
+ typename Iterator::pointer p (senf::storage_iterator(i));
+ // Manipulate the container by manipulating the data pointed at via 'p'
+ }
+
+ template <class Iterator>
+ void foo(Iterator i)
+ {
+ // ...
+ do( i, senf::contiguous_storage_iterator<Iterator>() );
+ // ...
+ }
+ \endcode
+
+ Thie \ref senf::storage_iterator helper function will convert an iterator to a pointer to
+ the same element the iterator is referencing.
This trait will return \c true for pointers. Additonally it should be configured to return
true for all standard containers which obey above implementation restrictions. This
To do so, the template must be specialized for those containers \c iterator type. If
compiling with g++, this is implemented in \ref IteratorTraits.ih. This file should be
- extended for further compilers if necessary.
+ extended for further compilers or STL implementations if needed.
*/
template <class RandomAccessIterator>
struct contiguous_storage_iterator
: public boost::false_type
{};
+ /** \brief Check for contiguous mutable storage. Pointer specialization
+
+ See \ref contiguous_storage_iterator.
+ */
template <class T>
struct contiguous_storage_iterator<T *>
: public boost::true_type
storage_iterator will convert a contiguous storage iterator into a pointer to the same
element in the container. This allows to directly access the containers storage.
+
+ \warning This conversion is only safe if \ref contiguous_storage_iterator<Iterator>::value
+ is \c true for the given iterator type !
*/
template <class Iterator>
typename std::iterator_traits<Iterator>::pointer storage_iterator(Iterator i);
BOOST_AUTO_UNIT_TEST(iteratorTraits)
{
BOOST_CHECK_EQUAL( senf::contiguous_storage_iterator<int*>::value, true );
+ BOOST_CHECK_EQUAL( senf::contiguous_storage_iterator<void>::value, false );
#ifdef __GNUG__
BOOST_CHECK_EQUAL( senf::contiguous_storage_iterator<std::vector<int>::iterator>::value, true);
BOOST_CHECK_EQUAL( senf::contiguous_storage_iterator<std::string::iterator>::value, true);
/** \mainpage The SENF Utilities Library
- The Utilities Library is a collection of independent
- utilities. We have
+ The Utilities Library is a collection of independent utilities. We have
+
<dl>
- <dt>\ref logger</dt><dd>highly flexible logging
- infrastructure</dd>
+ <dt>\ref logger</dt><dd>highly flexible logging infrastructure</dd>
- <dt>SystemException</dt><dd>standard exception for system errors
- (errno)</dd>
+ <dt>SystemException</dt><dd>standard exception for system errors (errno)</dd>
- <dt>\ref time</dt><dd>Very rudimentary microsecond time
- support</dd>
+ <dt>\ref time</dt><dd>Very rudimentary microsecond time support</dd>
- <dt>\ref process</dt><dd>Some simple process management and daemon
- helpers<?dd>
+ <dt>\ref process</dt><dd>Some simple process management and daemon helpers<?dd>
<dt>\ref membind</dt><dd>a simple <a
- href="http://www.boost.org/libs/bind/bind.html">Boost.Bind</a>
- extension</dd>
+ href="http://www.boost.org/libs/bind/bind.html">Boost.Bind</a> extension</dd>
- <dt>intrusive_refcount</dt><dd>mixin to simplify writing classes for
- use with <a
+ <dt>intrusive_refcount</dt><dd>mixin to simplify writing classes for use with <a
href="http://www.boost.org/libs/smart_ptr/intrusive_ptr.html">boost::intrusive_ptr</a></dd>
- <dt>SafeBool</dt><dd>a mixin class to provide a really safe
- replacement for <tt>operator bool</tt></dd>
+ <dt>SafeBool</dt><dd>a mixin class to provide a really safe replacement for <tt>operator
+ bool</tt></dd>
+
+ <dt>pool_alloc_mixin</dt><dd>mixin to provide pool allocation to a class</dd>
+
+ <dt>\ref singleton</dt><dd>mixin to make a class a singleton</dd>
+
+ <dt>prettyName()</dt><dd>an interface to the C++ demangler of g++ to get formated type names
+ from typeinfo objects</dd>
- <dt>prettyName()</dt><dd>an interface to the C++ demangler of g++
- to get formated type names from typeinfo objects</dd>
+ <dt>\ref SENF_SCOPED_BUFFER</dt><dd>a portable way to efficiently allocate temporary
+ buffers</dd>
- <dt>\ref SENF_SCOPED_BUFFER</dt><dd>a portable way to efficiently allocate temporary buffers</dd>
+ <dt>\ref contiguous_storage_iterator</dt><dd>traits class to check iterator type for raw pointer
+ accessibility</dd>
</dl>
*/
///////////////////////////////cti.p///////////////////////////////////////
template <typename T>
-prefix_ senf::SafeBool<T>::operator bool_type()
+prefix_ senf::ComparableSafeBool<T>::operator bool_type()
const
{
return (static_cast<const T*>(this))->boolean_test()
}
template <typename T>
-prefix_ bool senf::SafeBool<T>::operator!()
+prefix_ bool senf::ComparableSafeBool<T>::operator!()
const
{
return ! (static_cast<const T*>(this))->boolean_test();
}
template <typename T>
-prefix_ senf::SafeBool<T>::~SafeBool()
+prefix_ senf::ComparableSafeBool<T>::~ComparableSafeBool()
{}
template <typename T, typename U>
SafeBool to safe_bool (I tend to the latter ...)
*/
template <typename T>
- class SafeBool
+ class ComparableSafeBool
: public SafeBoolBase
{
public:
bool operator !() const;
protected:
- ~SafeBool();
+ ~ComparableSafeBool();
};
+ template <typename T>
+ class SafeBool : public ComparableSafeBool<T> {};
+
template <typename T, typename U>
void operator==(const SafeBool<T>& lhs,const SafeBool<U>& rhs);
#define prefix_ inline
///////////////////////////////cci.p///////////////////////////////////////
-prefix_ senf::intrusive_refcount::refcount_t senf::intrusive_refcount::refcount()
+prefix_ senf::intrusive_refcount_base::refcount_t senf::intrusive_refcount_base::refcount()
{
return refcount_;
}
-prefix_ bool senf::intrusive_refcount::is_shared()
+prefix_ bool senf::intrusive_refcount_base::is_shared()
{
return refcount()>1;
}
-prefix_ senf::intrusive_refcount::intrusive_refcount()
+prefix_ senf::intrusive_refcount_base::intrusive_refcount_base()
: refcount_(0)
{}
-prefix_ senf::intrusive_refcount::~intrusive_refcount()
+prefix_ senf::intrusive_refcount_base::~intrusive_refcount_base()
{}
-prefix_ void senf::intrusive_refcount::add_ref()
+prefix_ void senf::intrusive_refcount_base::add_ref()
{
++refcount_;
}
-prefix_ bool senf::intrusive_refcount::release()
+prefix_ bool senf::intrusive_refcount_base::release()
{
BOOST_ASSERT(refcount_>0);
return --refcount_ == 0;
}
-prefix_ void senf::intrusive_ptr_add_ref(intrusive_refcount* p)
-{
- p->add_ref();
-}
-
-prefix_ void senf::intrusive_ptr_release(intrusive_refcount* p)
-{
- if (p->release())
- delete p;
-}
+prefix_ senf::intrusive_refcount::intrusive_refcount()
+{}
///////////////////////////////cci.e///////////////////////////////////////
#undef prefix_
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of inline template functions
+/** \file
+ \brief intrusive_refcount inline template implementation */
-//#include "EthernetPacket.ih"
+//#include "intrusive_refcount.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <class Arg>
-prefix_ senf::EthernetPacket::EthernetPacket(Arg const & arg)
- : Packet(arg)
-{}
+template <class Self>
+prefix_ void senf::intrusive_refcount_t<Self>::intrusive_ptr_add_ref()
+{
+ static_cast<Self*>(this)->add_ref();
+}
+
+template <class Self>
+prefix_ void senf::intrusive_refcount_t<Self>::intrusive_ptr_release()
+{
+ if (static_cast<Self*>(this)->release()) delete this;
+}
+
+template <class Self>
+prefix_ void senf::intrusive_ptr_add_ref(intrusive_refcount_t<Self>* p)
+{
+ p->intrusive_ptr_add_ref();
+}
+
+template <class Self>
+prefix_ void senf::intrusive_ptr_release(intrusive_refcount_t<Self>* p)
+{
+ p->intrusive_ptr_release();
+}
-template <class Arg>
-prefix_ senf::EthVLanPacket::EthVLanPacket(Arg const & arg)
- : Packet(arg)
+template <class Self>
+prefix_ senf::intrusive_refcount_t<Self>::intrusive_refcount_t()
{}
///////////////////////////////cti.e///////////////////////////////////////
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
namespace senf {
- /** \brief Reference count mixin for intrusive_ptr
+ template <class Self> class intrusive_refcount_t;
- This class provides a simple internally managed refcount and supplies the <a
- href="http://www.boost.org/libs/smart_ptr/intrusive_ptr.html">boost::intrusive_ptr</a>
- required interface. To make a class compatible with \c boost::intrusive_ptr, just derive
- publicly from intrusive_refcount.
+ /** \brief Reference count mixin interface baseclass
- Two additional benefits of using intrusive_refcount are
- \li The object can access it's own refcount
- \li It is valid and safe to convert a plain object pointer to an intrusive_ptr at any time
- (not only after new)
+ This class is the baseclass of all intrusive refcount mixins. See \ref intrusive_refcount_t
+ and \ref intrusive_refcount for more information.
*/
- class intrusive_refcount
+ class intrusive_refcount_base
: public boost::noncopyable
{
public:
typedef unsigned refcount_t; ///< reference count type
- virtual ~intrusive_refcount();
+ virtual ~intrusive_refcount_base();
refcount_t refcount(); ///< current refcount
bool is_shared(); ///< return \c true if refcount() > 1
protected:
- intrusive_refcount();
+ intrusive_refcount_base();
- private:
void add_ref();
bool release();
+ private:
refcount_t refcount_;
+
+ };
+
+ /** \brief Customizable reference count mixin for intrusive_ptr
+
+ This class provides a simple internally managed refcount and supplies the <a
+ href="http://www.boost.org/libs/smart_ptr/intrusive_ptr.html">boost::intrusive_ptr</a>
+ required interface. To make a class compatible with \c boost::intrusive_ptr, just derive
+ publicly from intrusive_refcount_t.
+
+ \code
+ class SomeClass
+ : public intrusive_refcount_t<SomeClass>
+ {
+ // ...
+
+ private:
+ typedef intrusive_refcount_t<SomeClass> intrusive_base;
+
+ void add_ref()
+ {
+ // somehow call intrusive_base::add_ref()
+ }
+
+ bool release()
+ {
+ // Call intrusive_base::release() to decrement the
+ // refcount. This call will return 'true' when the refcount reaches 0.
+
+ // Return 'true', if the instance shall be deleted
+ }
+
+ // Needed to give intrusive_base access to 'add_ref' and 'release'
+ friend class intrusive_base;
+ };
+ \endcode
+
+ Two additional benefits of using intrusive_refcount are
+ \li The object can access it's own refcount
+ \li It is valid and safe to convert a plain object pointer to an intrusive_ptr at any time
+ (not only after new)
+
+ This class allows to customize the reference counting strategy (e.g. additional refcounting
+ within another object or checking some additional condition before deleting the object when
+ the refcount reaches 0).
+
+ The interface of this class is defined in \ref intrusive_refcount_base (which you should not
+ use directly).
+ */
+ template <class Self>
+ class intrusive_refcount_t
+ : public intrusive_refcount_base
+ {
+ protected:
+ intrusive_refcount_t();
+
+ private:
+ void intrusive_ptr_add_ref();
+ void intrusive_ptr_release();
+
+ template <class S>
+ friend void senf::intrusive_ptr_add_ref(intrusive_refcount_t<S> * p);
+ template <class S>
+ friend void senf::intrusive_ptr_release(intrusive_refcount_t<S> * p);
+ };
+
+ /** \brief Reference count mixin for intrusive_ptr
+
+ This class provides a simple internally managed refcount and supplies the <a
+ href="http://www.boost.org/libs/smart_ptr/intrusive_ptr.html">boost::intrusive_ptr</a>
+ required interface. To make a class compatible with \c boost::intrusive_ptr, just derive
+ publicly from intrusive_refcount.
- friend void senf::intrusive_ptr_add_ref(intrusive_refcount* p);
- friend void senf::intrusive_ptr_release(intrusive_refcount* p);
+ \code
+ class SomeClass
+ : public intrusive_refcount
+ {
+ // ...
+ };
+ \endcode
+
+ Two additional benefits of using intrusive_refcount are
+ \li The object can access it's own refcount
+ \li It is valid and safe to convert a plain object pointer to an intrusive_ptr at any time
+ (not only after new)
+
+ This mixin class directly uses the default allocation strategy. If you want to customize the
+ reference couting, use \ref intrusive_refcount_t.
+
+ The interface of this class is defined in \ref intrusive_refcount_t and \ref
+ intrusive_refcount_base (the latter of which you should not use directly).
+ */
+ class intrusive_refcount
+ : public intrusive_refcount_t<intrusive_refcount>
+ {
+ protected:
+ intrusive_refcount();
};
- void intrusive_ptr_add_ref(intrusive_refcount* p);
- void intrusive_ptr_release(intrusive_refcount* p);
+ template <class Self>
+ void intrusive_ptr_add_ref(intrusive_refcount_t<Self> * p);
+ template <class Self>
+ void intrusive_ptr_release(intrusive_refcount_t<Self> * p);
+
}
///////////////////////////////hh.e////////////////////////////////////////
#include "intrusive_refcount.cci"
//#include "intrusive_refcount.ct"
-//#include "intrusive_refcount.cti"
+#include "intrusive_refcount.cti"
#endif
\f
};
unsigned Tester::counter = 0;
+
+ struct TesterCustom
+ : public senf::intrusive_refcount_t<TesterCustom>
+ {
+ typedef boost::intrusive_ptr<TesterCustom> ptr;
+ typedef senf::intrusive_refcount_t<TesterCustom> super;
+
+ TesterCustom() { ++counter; }
+ ~TesterCustom() { --counter; }
+
+ void add_ref() { super::add_ref(); ++refs; }
+ bool release() { --refs; super::release(); return false; }
+
+ static unsigned counter;
+ static unsigned refs;
+ };
+
+ unsigned TesterCustom::counter = 0;
+ unsigned TesterCustom::refs = 0;
}
BOOST_AUTO_UNIT_TEST(intrusive_refcount)
BOOST_CHECK_EQUAL(Tester::counter,0u);
}
+BOOST_AUTO_UNIT_TEST(intrusive_refcount_t)
+{
+ BOOST_CHECK_EQUAL(TesterCustom::counter,0u);
+ BOOST_CHECK_EQUAL(TesterCustom::refs,0u);
+
+ TesterCustom::ptr p (new TesterCustom);
+ BOOST_CHECK_EQUAL(TesterCustom::counter,1u);
+ BOOST_CHECK_EQUAL(p->refcount(),1u);
+ BOOST_CHECK_EQUAL(p->is_shared(),false);
+ BOOST_CHECK_EQUAL(TesterCustom::refs,1u);
+
+
+ {
+ TesterCustom::ptr pp (p);
+ BOOST_CHECK_EQUAL(TesterCustom::counter,1u);
+ BOOST_CHECK_EQUAL(p->refcount(),2u);
+ BOOST_CHECK_EQUAL(p->is_shared(),true);
+ BOOST_CHECK_EQUAL(TesterCustom::refs,2u);
+ }
+
+ BOOST_CHECK_EQUAL(TesterCustom::counter,1u);
+ BOOST_CHECK_EQUAL(p->refcount(),1u);
+ BOOST_CHECK_EQUAL(p->is_shared(),false);
+ BOOST_CHECK_EQUAL(TesterCustom::refs,1u);
+
+ {
+ TesterCustom * pp (p.get());
+ p = 0;
+ BOOST_CHECK_EQUAL(TesterCustom::counter,1u);
+ BOOST_CHECK_EQUAL(TesterCustom::refs,0u);
+ // The TesterCustom leaks ...
+ delete pp;
+ BOOST_CHECK_EQUAL(TesterCustom::counter,0u);
+ }
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief pool_alloc_mixin inline template implementation */
+
+//#include "pool_alloc_mixin.ih"
+
+// Custom includes
+#include <boost/assert.hpp>
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+template <class Self>
+prefix_ void * senf::pool_alloc_mixin<Self>::operator new(size_t size)
+{
+ // When deriving from Self you may not change the class's size without
+ // inheriting from pool_alloc_mixin again. See pool_alloc_mixin documentation.
+ BOOST_ASSERT( size == sizeof(Self) );
+#ifndef NDEBUG
+ allocCounter(1);
+#endif
+ return boost::singleton_pool< pool_alloc_mixin_tag, sizeof(Self) >::malloc();
+}
+
+template <class Self>
+prefix_ void senf::pool_alloc_mixin<Self>::operator delete(void * p, size_t size)
+{
+ // When deriving from Self you may not change the class's size without
+ // inheriting from pool_alloc_mixin again. See pool_alloc_mixin documentation.
+ BOOST_ASSERT( size == sizeof(Self) );
+#ifndef NDEBUG
+ allocCounter(-1);
+#endif
+ boost::singleton_pool< pool_alloc_mixin_tag, sizeof(Self) >::free(p);
+}
+
+#ifndef NDEBUG
+
+template <class Self>
+prefix_ unsigned long senf::pool_alloc_mixin<Self>::allocCounter()
+{
+ return allocCounter(0);
+}
+
+template <class Self>
+prefix_ unsigned long senf::pool_alloc_mixin<Self>::allocCounter(long delta)
+{
+ static unsigned long counter (0);
+ counter += delta;
+ return counter;
+}
+
+#endif
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief pool_alloc_mixin public header */
+
+#ifndef HH_pool_alloc_mixin_
+#define HH_pool_alloc_mixin_ 1
+
+// Custom includes
+#include <boost/pool/singleton_pool.hpp>
+
+//#include "pool_alloc_mixin.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ struct pool_alloc_mixin_tag;
+
+ /** \brief Mixin to assign pool allocator to a class
+
+ This mixin will overload a classes <tt>operator new</tt> and <tt>operator delete</tt> so as
+ to make the class use the <a
+ href="http://www.boost.org/libs/pool/doc/index.html">Boost.Pool</a> memory allocator by
+ default. Using this allocator does however introduce a few restrictions:
+
+ \li The operator is defined for a fixed size. Therefore if you derive from the class <b>you
+ must not change it's size</t>.
+ \li If you change the size of the class in a derived class you have to derive from
+ pool_alloc_mixin again.
+
+ Usage:
+ \code
+ class SomeClass
+ : public senf::pool_alloc_mixin<SomeClass>
+ {
+ // ...
+ };
+ \endcode
+
+ \note pool_alloc_mixin uses the <a
+ href="http://www.boost.org/libs/pool/doc/index.html">Boost.Pool</a> <i>singleton
+ pool</i> interface with the tag <tt>pool_alloc_mixin_tag</tt>. This class is accessible
+ via the <tt>pool</tt> member. Using this member, it is simple to call relevant pool
+ functions, e.g. <tt>SomeClass::pool<>::release_memory()</tt>.
+ */
+ template <class Self>
+ class pool_alloc_mixin
+ {
+ public:
+ /** \brief Templated typedef for the pool used
+
+ Since the instantiation of the typedef must be delayed until Self is completely defined,
+ the simple typedef is replaced with a nested struct.
+ */
+ template <class T=void>
+ struct pool
+ : public boost::singleton_pool< pool_alloc_mixin_tag, sizeof(Self) >
+ {
+ typedef boost::singleton_pool< pool_alloc_mixin_tag, sizeof(Self) > type;
+ };
+
+ static void * operator new (size_t size);
+ ///< Operator new utilizing pool allocation
+ static void operator delete (void *p, size_t size);
+ ///< Operator delete utilizing pool allocation
+
+#ifndef NDEBUG
+ static unsigned long allocCounter();
+ private:
+ static unsigned long allocCounter(long delta);
+#endif
+ };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "pool_alloc_mixin.cci"
+//#include "pool_alloc_mixin.ct"
+#include "pool_alloc_mixin.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
-// $Id$
-//
-// Copyright (C) 2006
+// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Stefan Bund <g0dil@berlios.de>
//
// 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
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-// Definition of inline template functions
+/** \file
+ \brief singleton inline template implementation */
-//#include "RTPPacket.ih"
+//#include "singleton.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
-template <class Arg>
-prefix_ senf::RTPPacket::RTPPacket(Arg const & arg)
- : Packet(arg)
-{}
+template <class Self>
+prefix_ Self & senf::singleton<Self>::instance()
+{
+ static Self instance_;
+ creator_.nop(); // Force instantiation of force_creation
+ return instance_;
+}
+
+template <class Self>
+prefix_ senf::singleton<Self>::force_creation::force_creation()
+{
+ senf::singleton<Self>::instance(); // Force execution of instance() thereby creating instance
+}
-template <class Arg>
-prefix_ senf::RTPExtensionBasePacket::
-RTPExtensionBasePacket(Arg const & arg)
- : Packet(arg)
-{}
+template <class Self>
+prefix_ void senf::singleton<Self>::force_creation::nop()
+ const
+{
+ // No operation ...
+}
-template <class Arg>
-prefix_ senf::RTPUnknownExtensionPacket::
-RTPUnknownExtensionPacket(Arg const & arg)
- : RTPExtensionBasePacket(arg)
-{}
+template <class Self>
+typename senf::singleton<Self>::force_creation senf::singleton<Self>::create_;
///////////////////////////////cti.e///////////////////////////////////////
#undef prefix_
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// comment-column: 40
// End:
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief singleton public header */
+
+#ifndef HH_singleton_
+#define HH_singleton_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+
+//#include "singleton.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ /** \brief Mark a class as singleton and provide singleton accessor
+
+ This mixin class will mark a class as singleton and provide an accessor function to access
+ this singleton instance. The following preconditions must be met for this class to work as
+ advertised:
+ \li There must be only a single thread executing before main() starts. (This should always
+ be the case)
+ \li The singleton class must have a default constructor
+
+ If these conditions are met, this mixin will ensure that the singleton is constructed \e
+ before main even starts executing. If static construction code calls the instance() member,
+ it is ensured, that a valid instance is returned.
+
+ Usage example:
+ \code
+ class SomeClass
+ : public senf::singleton<SomeClass>
+ {
+ public:
+ SomeClass(); // Must have default constructor
+
+ // ...
+ };
+
+ int main(int argc, char ** argv)
+ {
+ // At this point, the instance has already been constructed
+
+ SomeClass::instance().doSomething();
+ }
+ \endcode
+
+ \note This implementation is directly taken from
+ <tt>boost/pool/detail/singleton.hpp</tt>. See that file for a description of the
+ technique. The only difference is, that I prefer to advertise this class as a mixin
+ (though it may be used the same way as the original too).
+ */
+ template <class Self>
+ class singleton
+ : boost::noncopyable
+ {
+ public:
+ static Self & instance(); ///< Return singleton instance
+
+ private:
+ /** \brief Internal
+ \internal
+ */
+ struct force_creation
+ {
+ force_creation();
+ void nop() const;
+ };
+
+ static force_creation creator_;
+ };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "singleton.cci"
+//#include "singleton.ct"
+//#include "singleton.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#ifdef _MSC_VER\r
+ #pragma warning (push)\r
+ //\r
+ //'function' : resolved overload was found by argument-dependent lookup\r
+ //A function found by argument-dependent lookup (Koenig lookup) was eventually \r
+ //chosen by overload resolution.\r
+ //\r
+ //In Visual C++ .NET and earlier compilers, a different function would have \r
+ //been called. To pick the original function, use an explicitly qualified name.\r
+ //\r
+\r
+ //warning C4275: non dll-interface class 'x' used as base for\r
+ //dll-interface class 'Y'\r
+ #pragma warning (disable : 4275)\r
+ //warning C4251: 'x' : class 'y' needs to have dll-interface to\r
+ //be used by clients of class 'z'\r
+ #pragma warning (disable : 4251)\r
+ #pragma warning (disable : 4675)\r
+ #pragma warning (disable : 4996)\r
+ #pragma warning (disable : 4503)\r
+ #pragma warning (disable : 4284) // odd return type for operator->\r
+ #pragma warning (disable : 4244) // possible loss of data\r
+ #pragma warning (disable : 4521) ////Disable "multiple copy constructors specified"\r
+ #pragma warning (disable : 4522)\r
+ #pragma warning (disable : 4146)\r
+ #pragma warning (disable : 4267) //conversion from 'X' to 'Y', possible loss of data\r
+#endif\r
+\r
+#include <boost/config.hpp>\r
+#include <boost/detail/workaround.hpp>\r
+\r
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))\r
+# pragma warn -8026 // shut up warning "cannot inline function because ..."\r
+# pragma warn -8027 // shut up warning "cannot inline function because ..."\r
+#endif\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#include <boost/config.hpp>\r
+#include <boost/detail/workaround.hpp>\r
+\r
+#if defined _MSC_VER\r
+ #pragma warning (pop)\r
+#endif\r
+\r
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))\r
+# pragma warn .8026\r
+# pragma warn .8027\r
+#endif\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright JoaquĆn M LĆ³pez MuƱoz 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#include <boost/type_traits/is_empty.hpp>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+template<typename T, bool IsEmpty = false>\r
+class ebo_holder_impl\r
+{\r
+ public:\r
+ ebo_holder_impl(){}\r
+ ebo_holder_impl(const T& t):t(t){}\r
+\r
+ T& get(){return t;}\r
+ const T& get()const{return t;}\r
+\r
+ private:\r
+ T t;\r
+};\r
+\r
+template<typename T>\r
+class ebo_holder_impl<T, true>\r
+ : private T\r
+{\r
+ public:\r
+ ebo_holder_impl(){}\r
+ ebo_holder_impl(const T& t):T(t){}\r
+\r
+ T& get(){return *this;}\r
+ const T& get()const{return *this;}\r
+};\r
+\r
+template<typename T>\r
+class ebo_holder\r
+ : public ebo_holder_impl<T,boost::is_empty<T>::value>\r
+{\r
+ private:\r
+ typedef ebo_holder_impl<T,boost::is_empty<T>::value> super;\r
+\r
+ public:\r
+ ebo_holder(){}\r
+ ebo_holder(const T& t):super(t){}\r
+\r
+ ebo_holder& operator=(const ebo_holder& x)\r
+ {\r
+ this->get()=x.get();\r
+ return *this;\r
+ }\r
+};\r
+\r
+\r
+} //namespace detail {\r
+} //namespace intrusive {\r
+} //namespace boost {\r
+\r
+/*\r
+\r
+// testing\r
+\r
+#include <boost/assert.hpp>\r
+#include <string>\r
+\r
+struct empty_member{};\r
+\r
+struct foo:public ebo_holder<empty_member>\r
+{\r
+ int x;\r
+};\r
+\r
+int main()\r
+{\r
+ ebo_holder<int> ei=5;\r
+ BOOST_ASSERT(ei.get()==5);\r
+ ei=6;\r
+ BOOST_ASSERT(ei.get()==6);\r
+\r
+ ebo_holder<std::string> es("hello");\r
+ BOOST_ASSERT(es.get()=="hello");\r
+ es=std::string("bye");\r
+ BOOST_ASSERT(es.get()=="bye");\r
+\r
+ BOOST_ASSERT(sizeof(foo)==sizeof(int)); // if EBO applies\r
+}\r
+*/\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#ifndef BOOST_INTRUSIVE_IHASHTABLE_HPP\r
+#define BOOST_INTRUSIVE_IHASHTABLE_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+//std C++\r
+#include <functional>\r
+#include <iterator>\r
+#include <utility>\r
+#include <algorithm>\r
+//boost\r
+#include <boost/utility.hpp>\r
+#include <boost/compressed_pair.hpp>\r
+#include <boost/assert.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <boost/functional/hash.hpp>\r
+//General intrusive utilities\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+//Implementation utilities\r
+#include <boost/intrusive/iunordered_set_hook.hpp>\r
+#include <boost/intrusive/islist.hpp>\r
+#include <cstddef>\r
+#include <iterator>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+template<int Dummy = 0>\r
+struct prime_list_holder\r
+{\r
+ static const std::size_t prime_list[];\r
+ static const std::size_t prime_list_size;\r
+};\r
+\r
+template<int Dummy>\r
+const std::size_t prime_list_holder<Dummy>::prime_list[] = {\r
+ 53ul, 97ul, 193ul, 389ul, 769ul,\r
+ 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,\r
+ 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,\r
+ 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,\r
+ 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,\r
+ 1610612741ul, 3221225473ul, 4294967291ul };\r
+\r
+template<int Dummy>\r
+const std::size_t prime_list_holder<Dummy>::prime_list_size\r
+ = sizeof(prime_list)/sizeof(std::size_t);\r
+\r
+//! The class template ihashtable is an intrusive hash table container, that\r
+//! is used to construct intrusive unordered_set and unordered_multiset containers. The\r
+//! no-throw guarantee holds only, if the Equal object and Hasher don't throw.\r
+template< class ValueTraits\r
+ , class Hash = boost::hash<typename ValueTraits::value_type>\r
+ , class Equal = std::equal_to<typename ValueTraits::value_type>\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t\r
+ >\r
+class ihashtable\r
+ : private detail::size_holder<ConstantTimeSize, SizeType>\r
+{\r
+ private:\r
+ template<class T, class Self, class NodeTraits>\r
+ class hashtable_iterator;\r
+\r
+ typedef islist<ValueTraits, false, SizeType> islist_impl;\r
+\r
+ struct bucket_type_impl\r
+ : private islist_impl\r
+ {\r
+ friend class ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>;\r
+\r
+ bucket_type_impl()\r
+ {}\r
+\r
+ bucket_type_impl(const bucket_type_impl &)\r
+ {}\r
+\r
+ bucket_type_impl &operator=(const bucket_type_impl&)\r
+ { islist_impl::clear(); }\r
+ };\r
+\r
+ static islist_impl &islist_from_bucket(bucket_type_impl &b)\r
+ { return static_cast<islist_impl&>(b); }\r
+\r
+ static const islist_impl &islist_from_bucket(const bucket_type_impl &b)\r
+ { return static_cast<const islist_impl&>(b); }\r
+\r
+ typedef ihashtable<ValueTraits, Hash, Equal\r
+ ,ConstantTimeSize, SizeType> this_type; \r
+ typedef typename ValueTraits::node_traits node_traits;\r
+ typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;\r
+\r
+ //noncopyable\r
+ ihashtable (const ihashtable&);\r
+ ihashtable operator =(const ihashtable&);\r
+\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits\r
+ <pointer>::difference_type difference_type;\r
+ typedef value_type key_type;\r
+ typedef Hash hasher;\r
+ typedef Equal key_equal;\r
+ typedef bucket_type_impl bucket_type;\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, bucket_type>::type bucket_ptr;\r
+ typedef typename islist_impl::iterator local_iterator;\r
+ typedef typename islist_impl::const_iterator const_local_iterator;\r
+\r
+ class const_iterator;\r
+ class iterator;\r
+\r
+ private:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <node_ptr, const node>::type const_node_ptr;\r
+ //typedef hashtable_algorithms<node_traits> node_algorithms;\r
+ typedef slist_algorithms<node_traits> node_algorithms;\r
+ enum { safemode_or_autounlink = \r
+ (int)ValueTraits::linking_policy == (int)auto_unlink ||\r
+ (int)ValueTraits::linking_policy == (int)safe_mode_link };\r
+\r
+ //Constant-time size is incompatible with auto-unlink hooks!\r
+ BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));\r
+\r
+ struct bucket_info_t\r
+ {\r
+ bucket_ptr buckets_;\r
+ size_type buckets_len_;\r
+ } ;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, bucket_info_t>::type bucket_info_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, const bucket_info_t>::type const_bucket_info_ptr;\r
+\r
+ //User scattered boost::compressed pair to get EBO all compilers\r
+ boost::compressed_pair\r
+ <boost::compressed_pair<bucket_info_t, Hash>\r
+ ,Equal> members_;\r
+\r
+ const Equal &priv_equal() const\r
+ { return members_.second(); }\r
+\r
+ Equal &priv_equal()\r
+ { return members_.second(); }\r
+\r
+ const_bucket_info_ptr priv_bucket_info() const\r
+ { return &members_.first().first(); }\r
+\r
+ bucket_info_ptr priv_bucket_info()\r
+ { return &members_.first().first(); }\r
+\r
+ const Hash &priv_hasher() const\r
+ { return members_.first().second(); }\r
+\r
+ Hash &priv_hasher()\r
+ { return members_.first().second(); }\r
+\r
+ const bucket_ptr &priv_buckets() const\r
+ { return members_.first().first().buckets_; }\r
+\r
+ bucket_ptr &priv_buckets()\r
+ { return members_.first().first().buckets_; }\r
+\r
+ const size_type &priv_buckets_len() const\r
+ { return members_.first().first().buckets_len_; }\r
+\r
+ size_type &priv_buckets_len()\r
+ { return members_.first().first().buckets_len_; }\r
+\r
+ static node_ptr uncast(const_node_ptr ptr)\r
+ {\r
+ using boost::get_pointer;\r
+ return node_ptr(const_cast<node*>(get_pointer(ptr)));\r
+ }\r
+\r
+ static bucket_info_ptr uncast(const_bucket_info_ptr ptr)\r
+ {\r
+ using boost::get_pointer;\r
+ return bucket_info_ptr(const_cast<bucket_info_t*>(get_pointer(ptr)));\r
+ }\r
+\r
+ template<class T, class Self, class NodeTraits>\r
+ class hashtable_iterator\r
+ : public std::iterator<std::forward_iterator_tag, T>\r
+ {\r
+ protected:\r
+ explicit hashtable_iterator\r
+ (local_iterator ptr, bucket_info_ptr bucket_info, size_type n_bucket)\r
+ : local_it_ (ptr), bucket_info_ (bucket_info), n_bucket_ (n_bucket)\r
+ {}\r
+\r
+ public:\r
+ hashtable_iterator ()\r
+ {}\r
+\r
+ Self& operator++()\r
+ {\r
+ using boost::get_pointer;\r
+ ++local_it_;\r
+ size_type buckets_len = bucket_info_->buckets_len_;\r
+ bucket_ptr buckets = bucket_info_->buckets_;\r
+ while (local_it_ == islist_from_bucket(buckets[n_bucket_]).end()){\r
+ if (++n_bucket_ == buckets_len){\r
+ local_it_ = invalid_local_it(*bucket_info_);\r
+ break;\r
+ }\r
+ local_it_ = islist_from_bucket(buckets[n_bucket_]).begin();\r
+ }\r
+ return static_cast<Self&> (*this);\r
+ }\r
+\r
+ Self operator++(int)\r
+ {\r
+ Self result(local_it_, bucket_info_, n_bucket_);\r
+ ++(*this);\r
+ return result;\r
+ }\r
+\r
+ bool operator== (const Self& i) const\r
+ { return local_it_ == i.local(); }\r
+\r
+ bool operator!= (const Self& i) const\r
+ { return !operator== (i); }\r
+\r
+ Self &set_internals\r
+ (local_iterator ptr, bucket_info_ptr bucket_info, size_type n_bucket)\r
+ {\r
+ local_it_ = ptr; bucket_info_ = bucket_info; n_bucket_ = n_bucket;\r
+ return static_cast<Self&>(*this);\r
+ }\r
+\r
+ local_iterator local() const\r
+ { return local_it_; }\r
+\r
+ bucket_info_ptr priv_bucket_info() const\r
+ { return bucket_info_; }\r
+\r
+ size_type bucket_num() const\r
+ { return n_bucket_; }\r
+\r
+ private:\r
+ local_iterator local_it_;\r
+ bucket_info_ptr bucket_info_;\r
+ size_type n_bucket_;\r
+ };\r
+\r
+ public:\r
+\r
+ class iterator\r
+ : public hashtable_iterator <value_type, iterator, node_traits>\r
+ {\r
+ private:\r
+ typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::pointer private_pointer;\r
+ typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::reference private_reference;\r
+ typedef hashtable_iterator<private_vt, iterator, node_traits> inherited;\r
+\r
+ public:\r
+ iterator()\r
+ {}\r
+\r
+ private_pointer operator->() const\r
+ { return &*this->local(); }\r
+\r
+ private_reference operator*() const\r
+ { return *this->local(); }\r
+\r
+ private:\r
+ explicit iterator\r
+ (local_iterator local_it, bucket_info_ptr bucket_info, size_type n_bucket)\r
+ : inherited(local_it, bucket_info, n_bucket)\r
+ {}\r
+\r
+ friend class ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>; \r
+ friend class hashtable_iterator<private_vt, iterator, node_traits>;\r
+ friend class const_iterator;\r
+ };\r
+\r
+ class const_iterator\r
+ : public hashtable_iterator<const value_type, const_iterator, node_traits>\r
+ {\r
+ private:\r
+ typedef const typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::const_pointer private_pointer;\r
+ typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::const_reference private_reference;\r
+ typedef hashtable_iterator<private_vt, const_iterator, node_traits> inherited;\r
+\r
+ public:\r
+ const_iterator()\r
+ {}\r
+\r
+ const_iterator(const typename ihashtable::iterator& it)\r
+ : inherited (it.local(), it.priv_bucket_info(), it.bucket_num())\r
+ {}\r
+\r
+ const_iterator & operator=(const typename ihashtable::iterator& it)\r
+ { return inherited::set_internals(it.local(), it.priv_bucket_info(), it.bucket_num()); }\r
+\r
+ private_pointer operator->() const\r
+ { return &*this->local(); }\r
+\r
+ private_reference operator*() const\r
+ { return *this->local(); }\r
+\r
+ private:\r
+ explicit const_iterator\r
+ (local_iterator ptr, bucket_info_ptr bucket_info, size_type n_bucket)\r
+ : inherited(ptr, bucket_info, n_bucket)\r
+ {}\r
+\r
+ friend class ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>; \r
+ friend class hashtable_iterator<private_vt, const_iterator, node_traits>;\r
+ };\r
+\r
+ //typedef typename node_algorithms::insert_commit_data insert_commit_data;\r
+ struct insert_commit_data\r
+ {\r
+ local_iterator prev_pos;\r
+ size_type bucket_num;\r
+ };\r
+\r
+ ihashtable( bucket_ptr buckets\r
+ , size_type buckets_len\r
+ , const Hash & hasher = Hash()\r
+ , const Equal &equal = Equal()) \r
+ : members_(boost::compressed_pair<bucket_info_t, Hash>(hasher)/*hasher*/, equal)\r
+ {\r
+ \r
+ BOOST_ASSERT(buckets_len != 0);\r
+ priv_buckets() = buckets;\r
+ priv_buckets_len() = buckets_len;\r
+ priv_clear_buckets();\r
+ size_traits::set_size(size_type(0));\r
+ }\r
+\r
+ ~ihashtable() \r
+ { this->clear(); }\r
+\r
+ iterator begin()\r
+ {\r
+ size_type bucket_num;\r
+ local_iterator local_it = priv_begin(bucket_num);\r
+ return iterator( local_it\r
+ , this->priv_bucket_info()\r
+ , bucket_num);\r
+ }\r
+\r
+ const_iterator begin() const\r
+ {\r
+ size_type bucket_num;\r
+ local_iterator local_it = priv_begin(bucket_num);\r
+ return const_iterator( local_it\r
+ , uncast(this->priv_bucket_info())\r
+ , bucket_num);\r
+ }\r
+\r
+ iterator end()\r
+ {\r
+ using boost::get_pointer;\r
+ bucket_info_t *info = get_pointer(this->priv_bucket_info());\r
+ return iterator(invalid_local_it(*info), 0, info->buckets_len_);\r
+ }\r
+\r
+ const_iterator end() const\r
+ {\r
+ using boost::get_pointer;\r
+ const bucket_info_t *info = get_pointer(this->priv_bucket_info());\r
+ return const_iterator(invalid_local_it(*info), 0, info->buckets_len_);\r
+ }\r
+\r
+ hasher hash_function() const\r
+ { return this->priv_hasher(); }\r
+\r
+ key_equal key_eq() const\r
+ { return this->priv_equal(); }\r
+\r
+ bool empty() const\r
+ {\r
+ if(ConstantTimeSize){\r
+ return !size();\r
+ }\r
+ else{\r
+ using boost::get_pointer;\r
+ size_type buckets_len = this->priv_buckets_len();\r
+ const bucket_type *b = get_pointer(this->priv_buckets());\r
+ for (size_type n = 0; n < buckets_len; ++n, ++b){\r
+ if(!b->empty()){\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ }\r
+\r
+ size_type size() const\r
+ {\r
+ if(ConstantTimeSize)\r
+ return size_traits::get_size();\r
+ else{\r
+ size_type len = 0;\r
+ using boost::get_pointer;\r
+ size_type buckets_len = this->priv_buckets_len();\r
+ const bucket_type *b = get_pointer(this->priv_buckets());\r
+ for (size_type n = 0; n < buckets_len; ++n, ++b){\r
+ len += b->size();\r
+ }\r
+ return len;\r
+ }\r
+ }\r
+\r
+ void swap(ihashtable& other)\r
+ {\r
+ using std::swap;\r
+ //These can throw\r
+ swap(this->priv_equal(), other.priv_equal());\r
+ swap(this->priv_hasher(), other.priv_hasher());\r
+ //These can't throw\r
+ swap(this->priv_buckets(), other.priv_buckets());\r
+ swap(this->priv_buckets_len(), other.priv_buckets_len());\r
+ if(ConstantTimeSize){\r
+ size_type backup = size_traits::get_size();\r
+ size_traits::set_size(other.get_size());\r
+ other.set_size(backup);\r
+ }\r
+ }\r
+\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const ihashtable &src, Cloner cloner, Destroyer destroyer)\r
+ {\r
+ this->clear_and_destroy(destroyer);\r
+ if(!ConstantTimeSize || !src.empty()){\r
+ const size_type src_bucket_count = src.bucket_count();\r
+ const size_type dst_bucket_count = this->bucket_count();\r
+\r
+ //If src bucket count is bigger or equal, structural copy is possible\r
+ if(src_bucket_count >= dst_bucket_count){\r
+ //First clone the first ones\r
+ const bucket_ptr src_buckets = src.priv_buckets();\r
+ const bucket_ptr dst_buckets = this->priv_buckets();\r
+ size_type constructed;\r
+ try{\r
+ for( constructed = 0\r
+ ; constructed < dst_bucket_count\r
+ ; ++constructed){\r
+ dst_buckets[constructed].clone_and_reverse_from(src_buckets[constructed], cloner, destroyer);\r
+ }\r
+ if(src_bucket_count != dst_bucket_count){\r
+ //Now insert the remaining ones using the modulo trick\r
+ for(//"constructed" comes from the previous loop\r
+ ; constructed < src_bucket_count\r
+ ; ++constructed){\r
+ bucket_type &dst_b = dst_buckets[constructed % dst_bucket_count];\r
+ bucket_type &src_b = src_buckets[constructed];\r
+ for( local_iterator b(src_b.begin()), e(src_b.end())\r
+ ; b != e\r
+ ; ++b){\r
+ dst_b.push_front(*cloner(*b));\r
+ }\r
+ }\r
+ }\r
+ }\r
+ catch(...){\r
+ while(constructed--){\r
+ dst_buckets[constructed].clear_and_destroy(destroyer);\r
+ }\r
+ throw;\r
+ }\r
+ size_traits::set_size(src.get_size());\r
+ }\r
+ else{\r
+ //Unlike previous cloning algorithm, this can throw\r
+ //if cloner, the hasher or comparison functor throw\r
+ const_iterator b(src.begin()), e(src.end());\r
+ try{\r
+ for(; b != e; ++b){\r
+ this->insert_equal(*cloner(*b));\r
+ }\r
+ }\r
+ catch(...){\r
+ this->clear_and_destroy(destroyer);\r
+ throw;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ iterator insert_equal(value_type &value)\r
+ {\r
+ size_type bucket_num;\r
+ local_iterator it = priv_find(value, this->priv_hasher(), this->priv_equal(), bucket_num);\r
+ bucket_type &b = this->priv_buckets()[bucket_num];\r
+ if(it == invalid_local_it(*this->priv_bucket_info())){\r
+ it = b.before_begin();\r
+ }\r
+ size_traits::increment();\r
+ return iterator(b.insert_after(it, value), this->priv_bucket_info(), bucket_num);\r
+ }\r
+\r
+ template<class Iterator>\r
+ void insert_equal(Iterator b, Iterator e)\r
+ {\r
+ for (; b != e; ++b)\r
+ this->insert_equal(*b);\r
+ }\r
+\r
+ std::pair<iterator, bool> insert_unique(value_type &value)\r
+ {\r
+ insert_commit_data commit_data;\r
+ std::pair<iterator, bool> ret = insert_unique_check(value, commit_data);\r
+ if(!ret.second)\r
+ return ret;\r
+ return std::pair<iterator, bool> (insert_unique_commit(value, commit_data), true);\r
+ }\r
+\r
+ template<class Iterator>\r
+ void insert_unique(Iterator b, Iterator e)\r
+ {\r
+ for (; b != e; ++b)\r
+ this->insert_unique(*b);\r
+ }\r
+\r
+ std::pair<iterator, bool> insert_unique_check\r
+ (const value_type &value, insert_commit_data &commit_data)\r
+ { return insert_unique_check(value, this->priv_hasher(), this->priv_equal(), commit_data); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<iterator, bool> insert_unique_check\r
+ ( const KeyType &key\r
+ , KeyHasher hasher\r
+ , KeyValueEqual key_value_eq\r
+ , insert_commit_data &commit_data)\r
+ {\r
+ commit_data.prev_pos = \r
+ priv_find(key, hasher, key_value_eq, commit_data.bucket_num);\r
+ bool success = commit_data.prev_pos == invalid_local_it(*this->priv_bucket_info());\r
+ if(success){\r
+ commit_data.prev_pos = this->priv_buckets()[commit_data.bucket_num].before_begin();\r
+ }\r
+ return std::pair<iterator, bool>\r
+ (iterator(commit_data.prev_pos, this->priv_bucket_info(), commit_data.bucket_num)\r
+ ,success);\r
+ }\r
+\r
+ iterator insert_unique_commit(value_type &value, const insert_commit_data &commit_data)\r
+ {\r
+ bucket_type &b = this->priv_buckets()[commit_data.bucket_num];\r
+ size_traits::increment();\r
+ return iterator( b.insert_after(commit_data.prev_pos, value)\r
+ , this->priv_bucket_info()\r
+ , commit_data.bucket_num);\r
+ }\r
+\r
+ void erase(const_iterator i)\r
+ { erase_and_destroy(i, detail::null_destroyer()); }\r
+\r
+ void erase(const_iterator b, const_iterator e)\r
+ { erase_and_destroy(b, e, detail::null_destroyer()); }\r
+\r
+ size_type erase(const value_type &value)\r
+ { return this->erase(value, this->priv_hasher(), this->priv_equal()); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return erase_and_destroy(key, hasher, equal, detail::null_destroyer()); }\r
+\r
+ template<class Destroyer>\r
+ void erase_and_destroy(const_iterator i, Destroyer destroyer)\r
+ {\r
+ local_iterator to_erase(i.local());\r
+ size_type n_bucket = i.bucket_num();\r
+ bucket_type &b = this->priv_buckets()[n_bucket];\r
+ b.erase_after_and_destroy(b.previous(to_erase), destroyer);\r
+ size_traits::decrement();\r
+ }\r
+\r
+ template<class Destroyer>\r
+ void erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer)\r
+ {\r
+ if(b == e) return;\r
+\r
+ //Get the bucket number and local iterator for both iterators\r
+ size_type first_bucket_num\r
+ = b.bucket_num();\r
+ local_iterator before_first_local_it\r
+ = priv_buckets()[first_bucket_num].previous(b.local());\r
+ size_type last_bucket_num;\r
+ local_iterator last_local_it;\r
+\r
+ //For the end iterator, we will assign the end iterator\r
+ //of the last bucket\r
+ if(e == end()){\r
+ last_bucket_num = this->bucket_count() - 1;\r
+ last_local_it = priv_buckets()[last_bucket_num].end();\r
+ }\r
+ else{\r
+ last_bucket_num = e.bucket_num();\r
+ last_local_it = e.local();\r
+ }\r
+\r
+ const bucket_ptr buckets = priv_buckets();\r
+ //First erase the nodes of the first bucket\r
+ {\r
+ bucket_type &first_b = buckets[first_bucket_num];\r
+ local_iterator nxt(before_first_local_it); ++nxt;\r
+ local_iterator end = first_b.end();\r
+ while(nxt != end){\r
+ nxt = first_b.erase_after_and_destroy(before_first_local_it, destroyer);\r
+ size_traits::decrement();\r
+ }\r
+ }\r
+\r
+ //Now fully clear the intermediate buckets\r
+ for(size_type i = first_bucket_num+1; i < last_bucket_num; ++i){\r
+ bucket_type &b = buckets[i];\r
+ if(b.empty())\r
+ continue;\r
+ local_iterator b_begin(b.before_begin());\r
+ local_iterator nxt(b_begin); ++nxt;\r
+ local_iterator end = b.end();\r
+ while(nxt != end){\r
+ nxt = b.erase_after_and_destroy(b_begin, destroyer);\r
+ size_traits::decrement();\r
+ }\r
+ }\r
+\r
+ //Now erase nodes from the last bucket\r
+ {\r
+ bucket_type &last_b = buckets[last_bucket_num];\r
+ local_iterator b_begin(last_b.before_begin());\r
+ local_iterator nxt(b_begin); ++nxt;\r
+ while(nxt != last_local_it){\r
+ nxt = last_b.erase_after_and_destroy(b_begin, destroyer);\r
+ size_traits::decrement();\r
+ }\r
+ }\r
+ }\r
+\r
+ template<class Destroyer>\r
+ size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { return erase_and_destroy(value, priv_hasher(), priv_equal(), destroyer); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual, class Destroyer>\r
+ size_type erase_and_destroy(const KeyType& key, KeyHasher hasher\r
+ ,KeyValueEqual equal, Destroyer destroyer)\r
+ {\r
+ size_type count(0);\r
+\r
+ if(ConstantTimeSize && this->empty()){\r
+ return 0;\r
+ }\r
+\r
+ bucket_type &b = this->priv_buckets()[hasher(key) % this->priv_buckets_len()];\r
+ local_iterator it = b.begin();\r
+ local_iterator prev = b.before_begin();\r
+\r
+ bool found = false;\r
+ //Find equal value\r
+ while(it != b.end()){\r
+ if(equal(key, *it)){\r
+ found = true;\r
+ break;\r
+ }\r
+ ++prev;\r
+ ++it;\r
+ }\r
+ \r
+ if(!found)\r
+ return 0;\r
+\r
+ //If found erase all equal values\r
+ for(local_iterator end = b.end(); it != end && equal(key, *it); ++count){\r
+ it = b.erase_after_and_destroy(prev, destroyer);\r
+ size_traits::decrement();\r
+ }\r
+ return count;\r
+ }\r
+\r
+ void clear()\r
+ {\r
+ if(safemode_or_autounlink){\r
+ priv_clear_buckets();\r
+ }\r
+ size_traits::set_size(size_type(0));\r
+ }\r
+\r
+ template<class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ {\r
+ if(!ConstantTimeSize || !this->empty()){\r
+ size_type num_buckets = this->bucket_count();\r
+ bucket_ptr b = this->priv_buckets();\r
+ for(; num_buckets--; ++b){\r
+ b->clear_and_destroy(destroyer);\r
+ }\r
+ size_traits::set_size(size_type(0));\r
+ }\r
+ }\r
+\r
+ size_type count(const value_type &value) const\r
+ { return this->count(value, this->priv_hasher(), this->priv_equal()); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ size_type count(const KeyType &key, const KeyHasher &hasher, const KeyValueEqual &equal) const\r
+ {\r
+ size_type bucket_n1, bucket_n2, count;\r
+ priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);\r
+ return count;\r
+ }\r
+\r
+ iterator find(const value_type &value)\r
+ { return find(value, this->priv_hasher(), this->priv_equal()); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ iterator find(const KeyType &key, KeyHasher hasher, KeyValueEqual equal)\r
+ {\r
+ size_type bucket_n;\r
+ local_iterator local_it = priv_find(key, hasher, equal, bucket_n);\r
+ return iterator( local_it\r
+ , this->priv_bucket_info()\r
+ , bucket_n);\r
+ }\r
+\r
+ const_iterator find(const value_type &value) const\r
+ { return find(value, this->priv_hasher(), this->priv_equal()); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ const_iterator find\r
+ (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const\r
+ {\r
+ size_type bucket_n;\r
+ local_iterator local_it = priv_find(key, hasher, equal, bucket_n);\r
+ return const_iterator( local_it\r
+ , uncast(this->priv_bucket_info())\r
+ , bucket_n);\r
+ }\r
+\r
+ std::pair<iterator,iterator> equal_range(const value_type &value)\r
+ { return this->equal_range(value, this->priv_hasher(), this->priv_equal()); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<iterator,iterator> equal_range\r
+ (const KeyType &key, KeyHasher hasher, KeyValueEqual equal)\r
+ {\r
+ size_type bucket_n1, bucket_n2, count;\r
+ std::pair<local_iterator, local_iterator> ret\r
+ = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);\r
+ return std::pair<iterator, iterator>\r
+ ( iterator( ret.first, this->priv_bucket_info(), bucket_n1)\r
+ , iterator( ret.second, this->priv_bucket_info(), bucket_n2) );\r
+ }\r
+\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const value_type &value) const\r
+ { return this->equal_range(value, this->priv_hasher(), this->priv_equal()); }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<const_iterator,const_iterator> equal_range\r
+ (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const\r
+ {\r
+ size_type bucket_n1, bucket_n2, count;\r
+ std::pair<local_iterator, local_iterator> ret\r
+ = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);\r
+ return std::pair<const_iterator, const_iterator>\r
+ ( const_iterator( ret.first, uncast(this->priv_bucket_info()), bucket_n1)\r
+ , const_iterator( ret.second, uncast(this->priv_bucket_info()), bucket_n2) );\r
+ }\r
+\r
+ size_type bucket_count() const\r
+ { return this->priv_buckets_len(); }\r
+\r
+ size_type bucket_size(size_type n)\r
+ { return this->priv_buckets()[n].size(); }\r
+\r
+ size_type bucket(const key_type& k)\r
+ { return this->bucket(k, this->priv_hasher()); }\r
+\r
+ template<class KeyType, class KeyHasher>\r
+ size_type bucket(const KeyType& k, const KeyHasher &hasher)\r
+ { return hasher(k) % this->priv_buckets_len(); }\r
+\r
+ bucket_ptr bucket_pointer() const\r
+ { return this->priv_buckets(); }\r
+\r
+ local_iterator begin(size_type n)\r
+ { return this->priv_buckets()[n].begin(); }\r
+\r
+ const_local_iterator begin(size_type n) const\r
+ { return const_cast<const bucket_type&>(this->priv_buckets()[n]).begin(); }\r
+\r
+ local_iterator end(size_type n)\r
+ { return this->priv_buckets()[n].end(); }\r
+\r
+ const_local_iterator end(size_type n) const\r
+ { return const_cast<const bucket_type&>(this->priv_buckets()[n]).end(); }\r
+\r
+ void rehash(bucket_ptr new_buckets, size_type new_buckets_len)\r
+ {\r
+ bucket_ptr old_buckets = this->priv_buckets();\r
+ size_type old_buckets_len = this->priv_buckets_len();\r
+\r
+ try{\r
+ size_type n = 0;\r
+ bool same_buffer = old_buckets == new_buckets;\r
+ //If we are shrinking the bucket array, just rehash the last nodes\r
+ if(same_buffer && (old_buckets_len > new_buckets_len)){\r
+ n = new_buckets_len;\r
+ }\r
+\r
+ //Iterate through nodes\r
+ for(; n < old_buckets_len; ++n){\r
+ bucket_type &old_bucket = old_buckets[n];\r
+ local_iterator before_i(old_bucket.before_begin());\r
+ local_iterator end(old_bucket.end());\r
+ local_iterator i(old_bucket.begin());\r
+ for(;i != end; ++i){\r
+ size_type new_n = this->priv_hasher()(*i) % new_buckets_len;\r
+ //If this is a buffer expansion don't move if it's not necessary\r
+ if(same_buffer && new_n == n){\r
+ ++before_i;\r
+ }\r
+ else{\r
+ bucket_type &new_b = new_buckets[new_n];\r
+ new_b.splice_after(new_b.before_begin(), old_bucket, before_i);\r
+ i = before_i;\r
+ }\r
+ }\r
+ }\r
+\r
+ this->priv_buckets() = new_buckets;\r
+ this->priv_buckets_len() = new_buckets_len;\r
+ }\r
+ catch(...){\r
+ for(size_type n = 0; n < new_buckets_len; ++n){\r
+ new_buckets[n].clear();\r
+ old_buckets[n].clear();\r
+ }\r
+ size_traits::set_size(size_type(0));\r
+ throw;\r
+ }\r
+ }\r
+\r
+ iterator current(value_type &value)\r
+ {\r
+ return iterator( bucket_type::current(value)\r
+ , this->priv_bucket_info()\r
+ , this->priv_hasher()(value) % this->priv_buckets_len());\r
+ }\r
+\r
+ const_iterator current(const value_type &value) const\r
+ {\r
+ return const_iterator( bucket_type::current(const_cast<value_type&>(value))\r
+ , uncast(this->priv_bucket_info())\r
+ , this->priv_hasher()(value) % this->priv_buckets_len());\r
+ }\r
+\r
+ static local_iterator current_local(value_type &value)\r
+ { return bucket_type::current(value); }\r
+\r
+ static const_local_iterator current_local(const value_type &value)\r
+ { return bucket_type::current(value); }\r
+\r
+ // no throw\r
+ static size_type suggested_upper_bucket_count(size_type n)\r
+ {\r
+ const std::size_t *primes = &prime_list_holder<0>::prime_list[0];\r
+ const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;\r
+ size_type const* bound =\r
+ std::lower_bound(primes, primes_end, n);\r
+ if(bound == primes_end)\r
+ bound--;\r
+ return size_type(*bound);\r
+ }\r
+\r
+ // no throw\r
+ static size_type suggested_lower_bucket_count(size_type n)\r
+ {\r
+ const std::size_t *primes = &prime_list_holder<0>::prime_list[0];\r
+ const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;\r
+ size_type const* bound =\r
+ std::upper_bound(primes, primes_end, n);\r
+ if(bound != primes_end)\r
+ bound--;\r
+ return size_type(*bound);\r
+ }\r
+\r
+ private:\r
+\r
+ static local_iterator invalid_local_it(const bucket_info_t &b)\r
+ { return b.buckets_->end(); }\r
+\r
+ local_iterator priv_begin(size_type &bucket_num) const\r
+ {\r
+ size_type buckets_len = this->priv_buckets_len();\r
+ for (bucket_num = 0; bucket_num < buckets_len; ++bucket_num){\r
+ bucket_type &b = this->priv_buckets()[bucket_num];\r
+ if(!b.empty())\r
+ return b.begin();\r
+ }\r
+ return invalid_local_it(*this->priv_bucket_info());\r
+ }\r
+\r
+ void priv_clear_buckets()\r
+ { priv_clear_buckets(this->priv_buckets(), this->priv_buckets_len()); }\r
+\r
+ static void priv_clear_buckets(bucket_ptr buckets_ptr, size_type buckets_len)\r
+ {\r
+ for(; buckets_len--; ++buckets_ptr){\r
+ buckets_ptr->clear();\r
+ }\r
+ }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ local_iterator priv_find\r
+ ( const KeyType &key, KeyHasher hasher\r
+ , KeyValueEqual equal, size_type &bucket_number) const\r
+ {\r
+ size_type b_len(this->priv_buckets_len());\r
+ bucket_number = hasher(key) % b_len;\r
+\r
+ if(ConstantTimeSize && this->empty()){\r
+ return invalid_local_it(*this->priv_bucket_info());\r
+ }\r
+ \r
+ bucket_type &b = this->priv_buckets()[bucket_number];\r
+ local_iterator it = b.begin();\r
+\r
+ while(it != b.end()){\r
+ if(equal(key, *it)){\r
+ return it;\r
+ }\r
+ ++it;\r
+ }\r
+\r
+ return invalid_local_it(*this->priv_bucket_info());\r
+ }\r
+\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<local_iterator, local_iterator> priv_equal_range\r
+ ( const KeyType &key\r
+ , KeyHasher hasher\r
+ , KeyValueEqual equal\r
+ , size_type &bucket_number_first\r
+ , size_type &bucket_number_second\r
+ , size_type &count) const\r
+ {\r
+ count = 0;\r
+ //Let's see if the element is present\r
+ std::pair<local_iterator, local_iterator> to_return\r
+ ( priv_find(key, hasher, equal, bucket_number_first)\r
+ , invalid_local_it(*this->priv_bucket_info()));\r
+ if(to_return.first == to_return.second){\r
+ bucket_number_second = bucket_number_first;\r
+ return to_return;\r
+ }\r
+ ++count;\r
+ //If it's present, find the first that it's not equal in\r
+ //the same bucket\r
+ bucket_type &b = this->priv_buckets()[bucket_number_first];\r
+ local_iterator it = to_return.first;\r
+ ++it;\r
+\r
+ while(it != b.end()){\r
+ if(!equal(key, *it)){\r
+ to_return.second = it;\r
+ bucket_number_second = bucket_number_first;\r
+ return to_return;\r
+ }\r
+ ++it;\r
+ ++count;\r
+ }\r
+ \r
+ //If we reached the end, find the first, non-empty bucket\r
+ for(bucket_number_second = bucket_number_first+1\r
+ ; bucket_number_second != this->priv_buckets_len()\r
+ ; ++bucket_number_second){\r
+ bucket_type &b = this->priv_buckets()[bucket_number_second];\r
+ if(!b.empty()){\r
+ to_return.second = b.begin();\r
+ return to_return;\r
+ }\r
+ }\r
+\r
+ //Otherwise, return the end node\r
+ to_return.second = invalid_local_it(*this->priv_bucket_info());\r
+ return to_return;\r
+ }\r
+};\r
+\r
+} //namespace detail\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_IHASHTABLE_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#ifndef BOOST_INTRUSIVE_IRBTREE_HPP\r
+#define BOOST_INTRUSIVE_IRBTREE_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <functional>\r
+#include <iterator>\r
+#include <boost/utility.hpp>\r
+#include <boost/compressed_pair.hpp>\r
+#include <utility>\r
+#include <boost/assert.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/iset_hook.hpp>\r
+#include <boost/intrusive/detail/rbtree_node.hpp>\r
+#include <boost/intrusive/detail/ebo_holder.hpp>\r
+#include <boost/intrusive/rbtree_algorithms.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <cstddef>\r
+#include <iterator>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+//! The class template irbtree is an intrusive red-black tree container, that\r
+//! is used to construct intrusive set and tree containers. The no-throw \r
+//! guarantee holds only, if the Compare object \r
+//! doesn't throw.\r
+template < class ValueTraits\r
+ , class Compare = std::less<typename ValueTraits::value_type>\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t\r
+ >\r
+class irbtree\r
+ : private detail::size_holder<ConstantTimeSize, SizeType>\r
+{\r
+ private:\r
+ typedef irbtree<ValueTraits, Compare\r
+ ,ConstantTimeSize, SizeType> this_type; \r
+ typedef typename ValueTraits::node_traits node_traits;\r
+ typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;\r
+\r
+ //noncopyable\r
+ irbtree (const irbtree&);\r
+ irbtree operator =(const irbtree&);\r
+\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits\r
+ <pointer>::difference_type difference_type;\r
+ typedef value_type key_type;\r
+ typedef Compare value_compare;\r
+ class iterator;\r
+ class const_iterator;\r
+ friend class iterator;\r
+ friend class const_iterator;\r
+\r
+ private:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <node_ptr, const node>::type const_node_ptr;\r
+ typedef rbtree_algorithms<node_traits> node_algorithms;\r
+ enum { safemode_or_autounlink = \r
+ (int)ValueTraits::linking_policy == (int)auto_unlink ||\r
+ (int)ValueTraits::linking_policy == (int)safe_mode_link };\r
+\r
+ //Constant-time size is incompatible with auto-unlink hooks!\r
+ BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));\r
+\r
+ template<class KeyValueCompare>\r
+ struct key_node_ptr_compare\r
+ : private ebo_holder<KeyValueCompare>\r
+ {\r
+ typedef ebo_holder<KeyValueCompare> base_t;\r
+ key_node_ptr_compare(KeyValueCompare kcomp)\r
+ : base_t(kcomp)\r
+ {}\r
+\r
+ template<class KeyType>\r
+ bool operator()(node_ptr node, const KeyType &key) const\r
+ { return base_t::get()(*ValueTraits::to_value_ptr(node), key); }\r
+\r
+ template<class KeyType>\r
+ bool operator()(const KeyType &key, node_ptr node) const\r
+ { return base_t::get()(key, *ValueTraits::to_value_ptr(node)); }\r
+\r
+ bool operator()(node_ptr node1, node_ptr node2) const\r
+ {\r
+ return base_t::get()\r
+ (*ValueTraits::to_value_ptr(node1), *ValueTraits::to_value_ptr(node2)); \r
+ }\r
+ };\r
+\r
+ //Use boost::compressed_pair to get EBO if possible\r
+ boost::compressed_pair<node, Compare> members_;\r
+ \r
+ const Compare &priv_comp() const\r
+ { return members_.second(); }\r
+\r
+ Compare &priv_comp()\r
+ { return members_.second(); }\r
+\r
+ const node &priv_header() const\r
+ { return members_.first(); }\r
+\r
+ node &priv_header()\r
+ { return members_.first(); }\r
+\r
+ template<class F>\r
+ struct value_to_node_cloner\r
+ : private ebo_holder<F>\r
+ {\r
+ typedef ebo_holder<F> base_t;\r
+ value_to_node_cloner(F f)\r
+ : base_t(f)\r
+ {}\r
+ \r
+ node_ptr operator()(node_ptr p)\r
+ { return ValueTraits::to_node_ptr(*base_t::get()(*ValueTraits::to_value_ptr(p))); }\r
+ };\r
+\r
+ template<class F>\r
+ struct value_to_node_destroyer\r
+ : private ebo_holder<F>\r
+ {\r
+ typedef ebo_holder<F> base_t;\r
+ value_to_node_destroyer(F f)\r
+ : base_t(f)\r
+ {}\r
+\r
+ void operator()(node_ptr p)\r
+ { base_t::get()(ValueTraits::to_value_ptr(p)); }\r
+ };\r
+\r
+ static node_ptr uncast(const_node_ptr ptr)\r
+ {\r
+ using boost::get_pointer;\r
+ return node_ptr(const_cast<node*>(get_pointer(ptr)));\r
+ }\r
+\r
+ public:\r
+ typedef typename node_algorithms::insert_commit_data insert_commit_data;\r
+\r
+ class iterator\r
+ : public detail::rbtree_iterator <value_type, iterator, node_traits>\r
+ {\r
+ private:\r
+ typedef typename irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>::pointer private_pointer;\r
+ typedef typename irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>::reference private_reference;\r
+ typedef detail::rbtree_iterator<private_vt, iterator, node_traits> inherited;\r
+\r
+ public:\r
+ iterator ()\r
+ {}\r
+\r
+ private_pointer operator->() const\r
+ { return ValueTraits::to_value_ptr(this->tree_node()); }\r
+\r
+ private_reference operator*() const\r
+ { return *ValueTraits::to_value_ptr(this->tree_node()); }\r
+\r
+ private:\r
+ explicit iterator(node_ptr node)\r
+ : inherited(node)\r
+ {}\r
+ \r
+ friend class irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>; \r
+ friend class detail::rbtree_iterator<private_vt, iterator, node_traits>;\r
+ friend class const_iterator;\r
+ };\r
+\r
+ class const_iterator\r
+ : public detail::rbtree_iterator<const value_type, const_iterator, node_traits>\r
+ {\r
+ private:\r
+ typedef const typename irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>::const_pointer private_pointer;\r
+ typedef typename irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>::const_reference private_reference;\r
+ typedef detail::rbtree_iterator<private_vt, const_iterator, node_traits> inherited;\r
+\r
+ public:\r
+ const_iterator ()\r
+ {}\r
+\r
+ const_iterator(const typename irbtree::iterator& it)\r
+ : inherited (it.tree_node())\r
+ {}\r
+\r
+ const_iterator & operator=(const typename irbtree::iterator& it)\r
+ { return inherited::operator=(it.tree_node()); }\r
+\r
+ private_pointer operator->()\r
+ { return ValueTraits::to_value_ptr(this->tree_node()); }\r
+\r
+ private_reference operator*()\r
+ { return *ValueTraits::to_value_ptr(this->tree_node()); }\r
+\r
+ private:\r
+ explicit const_iterator (const_node_ptr p)\r
+ : inherited (uncast(p))\r
+ {}\r
+\r
+ friend class irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType>; \r
+ friend class detail::rbtree_iterator<private_vt, const_iterator, node_traits>;\r
+ };\r
+\r
+ typedef std::reverse_iterator<iterator> reverse_iterator;\r
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: Constructs an empty tree. \r
+ //! \r
+ //! <b>Complexity</b>: Constant. \r
+ //! \r
+ //! <b>Throws</b>: Nothing unless the copy constructor of the Compare object throws. \r
+ irbtree(Compare cmp = Compare()) \r
+ : members_(cmp)\r
+ { \r
+ node_algorithms::init_header(&priv_header()); \r
+ size_traits::set_size(size_type(0));\r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type. \r
+ //! cmp must be a comparison function that induces a strict weak ordering.\r
+ //! \r
+ //! <b>Effects</b>: Constructs an empty tree and inserts elements from \r
+ //! [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using \r
+ //! comp and otherwise N * log N, where N is last Ā first.\r
+ //! \r
+ //! <b>Throws</b>: Nothing unless the copy constructor of the Compare object throws. \r
+ template<class Iterator>\r
+ irbtree(bool unique, Iterator b, Iterator e, Compare cmp = Compare())\r
+ : members_(cmp)\r
+ {\r
+ node_algorithms::init_header(&priv_header());\r
+ size_traits::set_size(size_type(0));\r
+ if(unique)\r
+ this->insert_unique(b, e);\r
+ else\r
+ this->insert_equal(b, e);\r
+ }\r
+\r
+ //! <b>Effects</b>: Detaches all elements from this. The objects in the set \r
+ //! are not deleted (i.e. no destructors are called), but the nodes according to \r
+ //! the ValueTraits template parameter are reinitialized and thus can be reused. \r
+ //! \r
+ //! <b>Complexity</b>: Linear to elements contained in *this. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~irbtree() \r
+ { this->clear(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the beginning of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator begin()\r
+ { return iterator (node_traits::get_left(node_ptr(&priv_header()))); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the beginning of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator begin() const\r
+ { return const_iterator (node_traits::get_left(const_node_ptr(&priv_header()))); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the end of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator end()\r
+ { return iterator (node_ptr(&priv_header())); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the end of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator end() const\r
+ { return const_iterator (const_node_ptr(&priv_header())); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning of the\r
+ //! reversed tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ reverse_iterator rbegin()\r
+ { return reverse_iterator(end()); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning\r
+ //! of the reversed tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_reverse_iterator rbegin() const\r
+ { return const_reverse_iterator(end()); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end\r
+ //! of the reversed tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ reverse_iterator rend()\r
+ { return reverse_iterator(begin()); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end\r
+ //! of the reversed tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_reverse_iterator rend() const\r
+ { return const_reverse_iterator(begin()); }\r
+\r
+ //! <b>Effects</b>: Returns the value_compare object used by the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If value_compare copy-constructor throws.\r
+ value_compare value_comp() const\r
+ { return priv_comp(); }\r
+\r
+ //! <b>Effects</b>: Returns true is the container is empty.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bool empty() const\r
+ { return node_algorithms::unique(const_node_ptr(&priv_header())); }\r
+\r
+ //! <b>Effects</b>: Returns the number of elements stored in the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to elements contained in *this.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type size() const\r
+ {\r
+ if(ConstantTimeSize)\r
+ return size_traits::get_size();\r
+ else\r
+ return empty() ? 0 : node_algorithms::count(node_traits::get_parent(const_node_ptr(&priv_header())));\r
+ }\r
+\r
+ //! <b>Effects</b>: Swaps the contents of two multisets.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the comparison functor's unspecified swap call throws.\r
+ void swap(irbtree& other)\r
+ {\r
+ //This can throw\r
+ using std::swap;\r
+ swap(priv_comp(), priv_comp());\r
+ //These can't throw\r
+ node_algorithms::swap_tree(node_ptr(&priv_header()), node_ptr(&other.priv_header()));\r
+ if(ConstantTimeSize){\r
+ size_type backup = size_traits::get_size();\r
+ size_traits::set_size(other.get_size());\r
+ other.set_size(backup);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Inserts value into the tree before the upper bound.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert_equal_upper_bound(value_type &value)\r
+ {\r
+ key_node_ptr_compare<value_compare> key_node_comp(priv_comp());\r
+ node_ptr to_insert(ValueTraits::to_node_ptr(value));\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ size_traits::increment();\r
+ return iterator(node_algorithms::insert_equal_upper_bound\r
+ (node_ptr(&priv_header()), to_insert, key_node_comp));\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Inserts value into the tree before the lower bound.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert_equal_lower_bound(value_type &value)\r
+ {\r
+ key_node_ptr_compare<value_compare> key_node_comp(priv_comp());\r
+ node_ptr to_insert(ValueTraits::to_node_ptr(value));\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ size_traits::increment();\r
+ return iterator(node_algorithms::insert_equal_lower_bound\r
+ (node_ptr(&priv_header()), to_insert, key_node_comp));\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue, and "hint" must be\r
+ //! a valid iterator.\r
+ //! \r
+ //! <b>Effects</b>: Inserts x into the tree, using "hint" as a hint to\r
+ //! where it will be inserted. If "hint" is the upper_bound\r
+ //! the insertion takes constant time (two comparisons in the worst case)\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic in general, but it is amortized\r
+ //! constant time if t is inserted immediately before hint.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert_equal(const_iterator hint, value_type &value)\r
+ {\r
+ key_node_ptr_compare<value_compare> key_node_comp(priv_comp());\r
+ node_ptr to_insert(ValueTraits::to_node_ptr(value));\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ size_traits::increment();\r
+ return iterator(node_algorithms::insert_equal\r
+ (node_ptr(&priv_header()), hint.tree_node(), to_insert, key_node_comp));\r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue \r
+ //! of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Inserts a each element of a range into the tree\r
+ //! before the upper bound of the key of each element.\r
+ //! \r
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the \r
+ //! size of the range. However, it is linear in N if the range is already sorted \r
+ //! by value_comp().\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ template<class Iterator>\r
+ void insert_equal(Iterator b, Iterator e)\r
+ {\r
+ if(this->empty()){\r
+ iterator end(this->end());\r
+ for (; b != e; ++b)\r
+ this->insert_equal(end, *b);\r
+ }\r
+ else{\r
+ for (; b != e; ++b)\r
+ this->insert_equal_upper_bound(*b);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Inserts value into the tree if the value\r
+ //! is not already present.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ std::pair<iterator, bool> insert_unique(value_type &value)\r
+ {\r
+ insert_commit_data commit_data;\r
+ std::pair<iterator, bool> ret = insert_unique_check(value, commit_data);\r
+ if(!ret.second)\r
+ return ret;\r
+ return std::pair<iterator, bool> (insert_unique_commit(value, commit_data), true);\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue, and "hint" must be\r
+ //! a valid iterator\r
+ //! \r
+ //! <b>Effects</b>: Tries to insert x into the tree, using "hint" as a hint\r
+ //! to where it will be inserted.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic in general, but it is amortized\r
+ //! constant time (two comparisons in the worst case)\r
+ //! if t is inserted immediately before hint.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert_unique(const_iterator hint, value_type &value)\r
+ {\r
+ insert_commit_data commit_data;\r
+ std::pair<iterator, bool> ret = insert_unique_check(hint, value, commit_data);\r
+ if(!ret.second)\r
+ return ret.first;\r
+ return insert_unique_commit(value, commit_data);\r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue \r
+ //! of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Tries to insert each element of a range into the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the \r
+ //! size of the range. However, it is linear in N if the range is already sorted \r
+ //! by value_comp().\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ template<class Iterator>\r
+ void insert_unique(Iterator b, Iterator e)\r
+ {\r
+ if(this->empty()){\r
+ iterator end(this->end());\r
+ for (; b != e; ++b)\r
+ this->insert_unique(end, *b);\r
+ }\r
+ else{\r
+ for (; b != e; ++b)\r
+ this->insert_unique(*b);\r
+ }\r
+ }\r
+\r
+ std::pair<iterator, bool> insert_unique_check\r
+ (const value_type &value, insert_commit_data &commit_data)\r
+ { return insert_unique_check(value, priv_comp(), commit_data); }\r
+\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator, bool> insert_unique_check\r
+ (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data)\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> comp(key_value_comp);\r
+ std::pair<node_ptr, bool> ret = \r
+ (node_algorithms::insert_unique_check\r
+ (node_ptr(&priv_header()), key, comp, commit_data));\r
+ return std::pair<iterator, bool>(iterator(ret.first), ret.second);\r
+ }\r
+\r
+ std::pair<iterator, bool> insert_unique_check\r
+ (const_iterator hint, const value_type &value, insert_commit_data &commit_data)\r
+ { return insert_unique_check(hint, value, priv_comp(), commit_data); }\r
+\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator, bool> insert_unique_check\r
+ (const_iterator hint, const KeyType &key\r
+ ,KeyValueCompare key_value_comp, insert_commit_data &commit_data)\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> comp(key_value_comp);\r
+ std::pair<node_ptr, bool> ret = \r
+ (node_algorithms::insert_unique_check\r
+ (node_ptr(&priv_header()), hint.tree_node(), key, comp, commit_data));\r
+ return std::pair<iterator, bool>(iterator(ret.first), ret.second);\r
+ }\r
+\r
+ iterator insert_unique_commit(value_type &value, const insert_commit_data &commit_data)\r
+ {\r
+ node_ptr to_insert(ValueTraits::to_node_ptr(value));\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ size_traits::increment();\r
+ node_algorithms::insert_unique_commit\r
+ (node_ptr(&priv_header()), to_insert, commit_data);\r
+ return iterator(to_insert);\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed to by pos. \r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase element is constant time. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ iterator erase(iterator i)\r
+ {\r
+ iterator ret(i);\r
+ ++ret;\r
+ node_ptr to_erase(i.tree_node());\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(!node_algorithms::unique(to_erase));\r
+ node_algorithms::erase(&priv_header(), to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ return ret;\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e. \r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase range is at most \r
+ //! O(log(size() + N)), where N is the number of elements in the range.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ iterator erase(iterator b, iterator e)\r
+ { size_type n; return private_erase(b, e, n); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + N).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ size_type erase(const value_type &value)\r
+ { return this->erase(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements with the given key.\r
+ //! according to the comparison functor "comp".\r
+ //!\r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + N).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class KeyType, class KeyValueCompare>\r
+ size_type erase(const KeyType& key, KeyValueCompare comp)\r
+ {\r
+ std::pair<iterator,iterator> p = this->equal_range(key, comp);\r
+ size_type n;\r
+ private_erase(p.first, p.second, n);\r
+ return n;\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed to by pos. \r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase element is constant time. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators \r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator i, Destroyer destroyer)\r
+ {\r
+ node_ptr to_erase(i.tree_node());\r
+ iterator ret(this->erase(i));\r
+ destroyer(ValueTraits::to_value_ptr(to_erase));\r
+ return ret;\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase range is at most \r
+ //! O(log(size() + N)), where N is the number of elements in the range.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer)\r
+ { size_type n; return private_erase(b, e, n, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + N).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+ {\r
+ std::pair<iterator,iterator> p = this->equal_range(value);\r
+ size_type n;\r
+ private_erase(p.first, p.second, n, destroyer);\r
+ return n;\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given key.\r
+ //! according to the comparison functor "comp".\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + N).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class KeyType, class KeyValueCompare, class Destroyer>\r
+ size_type erase_and_destroy(const KeyType& key, KeyValueCompare comp, Destroyer destroyer)\r
+ {\r
+ std::pair<iterator,iterator> p = this->equal_range(key, comp);\r
+ size_type n;\r
+ private_erase(p.first, p.second, n, destroyer);\r
+ return n;\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases all of the elements. \r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void clear()\r
+ {\r
+ if(safemode_or_autounlink){\r
+ while(1){\r
+ node_ptr leftmost\r
+ (node_algorithms::unlink_leftmost_without_rebalance\r
+ (node_ptr(&priv_header())));\r
+ if(!leftmost)\r
+ break;\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(leftmost);\r
+ }\r
+ }\r
+ else{\r
+ node_algorithms::init_header(&priv_header());\r
+ size_traits::set_size(0);\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases all of the elements calling destroyer(p) for\r
+ //! each node to be erased.\r
+ //! <b>Complexity</b>: Average complexity for is at most O(log(size() + N)),\r
+ //! where N is the number of elements in the container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. Calls N times to destroyer functor.\r
+ template<class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ {\r
+ while(1){\r
+ node_ptr leftmost\r
+ (node_algorithms::unlink_leftmost_without_rebalance\r
+ (node_ptr(&priv_header())));\r
+ if(!leftmost)\r
+ break;\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(leftmost);\r
+ destroyer(ValueTraits::to_value_ptr(leftmost));\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given value\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal\r
+ //! to number of objects with the given value.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type count(const value_type &value) const\r
+ { return this->count(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given key\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal\r
+ //! to number of objects with the given key.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ size_type count(const KeyType &key, KeyValueCompare comp) const\r
+ {\r
+ std::pair<const_iterator, const_iterator> ret = this->equal_range(key, comp);\r
+ return std::distance(ret.first, ret.second);\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator lower_bound(const value_type &value)\r
+ { return this->lower_bound(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator lower_bound(const value_type &value) const\r
+ { return this->lower_bound(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator lower_bound(const KeyType &key, KeyValueCompare comp)\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ return iterator(node_algorithms::lower_bound\r
+ (const_node_ptr(&priv_header()), key, key_node_comp));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a const iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator lower_bound(const KeyType &key, KeyValueCompare comp) const\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ return const_iterator(node_algorithms::lower_bound\r
+ (const_node_ptr(&priv_header()), key, key_node_comp));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator upper_bound(const value_type &value)\r
+ { return this->upper_bound(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k according to comp or end() if that element\r
+ //! does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator upper_bound(const KeyType &key, KeyValueCompare comp)\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ return iterator(node_algorithms::upper_bound\r
+ (const_node_ptr(&priv_header()), key, key_node_comp));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator upper_bound(const value_type &value) const\r
+ { return this->upper_bound(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k according to comp or end() if that element\r
+ //! does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator upper_bound(const KeyType &key, KeyValueCompare comp) const\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ return const_iterator(node_algorithms::upper_bound\r
+ (const_node_ptr(&priv_header()), key, key_node_comp));\r
+ }\r
+\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! k or end() if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator find(const value_type &value)\r
+ { return this->find(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! k or end() if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator find(const KeyType &key, KeyValueCompare comp)\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ return iterator\r
+ (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp));\r
+ }\r
+\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose key is \r
+ //! k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator find(const value_type &value) const\r
+ { return this->find(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose key is \r
+ //! k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator find(const KeyType &key, KeyValueCompare comp) const\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ return const_iterator\r
+ (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp));\r
+ }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ std::pair<iterator,iterator> equal_range(const value_type &value)\r
+ { return this->equal_range(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator,iterator> equal_range(const KeyType &key, KeyValueCompare comp)\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ std::pair<node_ptr, node_ptr> ret\r
+ (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp));\r
+ return std::pair<iterator, iterator>(iterator(ret.first), iterator(ret.second));\r
+ }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const value_type &value) const\r
+ { return this->equal_range(value, priv_comp()); }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const KeyType &key, KeyValueCompare comp) const\r
+ {\r
+ key_node_ptr_compare<KeyValueCompare> key_node_comp(comp);\r
+ std::pair<node_ptr, node_ptr> ret\r
+ (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp));\r
+ return std::pair<const_iterator, const_iterator>(const_iterator(ret.first), const_iterator(ret.second));\r
+ }\r
+\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const irbtree &src, Cloner cloner, Destroyer destroyer)\r
+ {\r
+ this->clear_and_destroy(destroyer);\r
+ if(!src.empty()){\r
+ node_algorithms::clone_tree\r
+ (const_node_ptr(&src.priv_header())\r
+ ,node_ptr(&this->priv_header())\r
+ ,value_to_node_cloner<Cloner>(cloner)\r
+ ,value_to_node_destroyer<Destroyer>(destroyer));\r
+ size_traits::set_size(src.get_size());\r
+ }\r
+ }\r
+\r
+ pointer unlink_leftmost_without_rebalance()\r
+ {\r
+ node_ptr to_destroy(node_algorithms::unlink_leftmost_without_rebalance\r
+ (node_ptr(&priv_header())));\r
+ if(!to_destroy)\r
+ return 0;\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_destroy);\r
+ return ValueTraits::to_value_ptr(to_destroy);\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the set\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static iterator current(value_type &value)\r
+ { return iterator (ValueTraits::to_node_ptr(value)); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the\r
+ //! set that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_iterator current(const value_type &value) \r
+ { return const_iterator (ValueTraits::to_node_ptr(const_cast<value_type&> (value))); }\r
+/*\r
+ //! <b>Requires</b>: value shall not be in a tree of the appropriate type.\r
+ //! \r
+ //! <b>Effects</b>: init_node post-constructs the node data in x used by multisets of \r
+ //! the appropriate type. For the accessors multiset_derived_node and multiset_member_node \r
+ //! init_node has no effect, since the constructors of multiset_node_d and multiset_node_m \r
+ //! have already initialized the node data. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: This function is meant to be used mainly with the member value_traits, \r
+ //! where no implicit node initialization during construction occurs.\r
+ static void init_node(reference value)\r
+ { node_algorithms::init(node_ptr(&*ValueTraits::to_node_ptr(value))); }\r
+\r
+ //! <b>Effects</b>: removes x from a tree of the appropriate type. It has no effect,\r
+ //! if x is not in such a tree. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: This static function is only usable with the "safe mode"\r
+ //! hook and non-constant time size lists. Otherwise, the user must use\r
+ //! the non-static "erase(value_type &)" member. If the user calls\r
+ //! this function with a non "safe mode" or constant time size list\r
+ //! a compilation error will be issued.\r
+ template<class T>\r
+ static void remove_node(T& value)\r
+ {\r
+ //This function is only usable for safe mode hooks and non-constant\r
+ //time lists. \r
+ //BOOST_STATIC_ASSERT((!(safemode_or_autounlink && ConstantTimeSize)));\r
+ BOOST_STATIC_ASSERT((!ConstantTimeSize));\r
+ BOOST_STATIC_ASSERT((boost::is_convertible<T, value_type>::value));\r
+ node_ptr to_remove(ValueTraits::to_node_ptr(value));\r
+ node_algorithms::unlink_and_rebalance(to_remove);\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_remove);\r
+ }\r
+*/\r
+ private:\r
+ template<class Destroyer>\r
+ iterator private_erase(iterator b, iterator e, size_type &n, Destroyer destroyer)\r
+ {\r
+ for(n = 0; b != e; ++n)\r
+ this->erase_and_destroy(b++, destroyer);\r
+ return b;\r
+ }\r
+\r
+ iterator private_erase(iterator b, iterator e, size_type &n)\r
+ {\r
+ for(n = 0; b != e; ++n)\r
+ this->erase(b++);\r
+ return b;\r
+ }\r
+};\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator==(const irbtree<V, P, C, S>& x, const irbtree<V, P, C, S>& y)\r
+{\r
+ if(C && x.size() != y.size()){\r
+ return false;\r
+ }\r
+ typedef typename irbtree<V, P, C, S>::const_iterator const_iterator;\r
+ const_iterator end1 = x.end();\r
+\r
+ const_iterator i1 = x.begin();\r
+ const_iterator i2 = y.begin();\r
+ if(C){\r
+ while (i1 != end1 && *i1 == *i2) {\r
+ ++i1;\r
+ ++i2;\r
+ }\r
+ return i1 == end1;\r
+ }\r
+ else{\r
+ const_iterator end2 = y.end();\r
+ while (i1 != end1 && i2 != end2 && *i1 == *i2) {\r
+ ++i1;\r
+ ++i2;\r
+ }\r
+ return i1 == end1 && i2 == end2;\r
+ }\r
+}\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator<(const irbtree<V, P, C, S>& x,\r
+ const irbtree<V, P, C, S>& y)\r
+{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator!=(const irbtree<V, P, C, S>& x, const irbtree<V, P, C, S>& y) \r
+{ return !(x == y); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator>(const irbtree<V, P, C, S>& x, const irbtree<V, P, C, S>& y) \r
+{ return y < x; }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator<=(const irbtree<V, P, C, S>& x, const irbtree<V, P, C, S>& y) \r
+{ return !(y < x); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator>=(const irbtree<V, P, C, S>& x, const irbtree<V, P, C, S>& y) \r
+{ return !(x < y); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline void swap(irbtree<V, P, C, S>& x, irbtree<V, P, C, S>& y)\r
+{ x.swap(y); }\r
+\r
+} //namespace detail\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_IRBTREE_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_LIST_NODE_HPP\r
+#define BOOST_INTRUSIVE_LIST_NODE_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <iterator>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/list_algorithms.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <cstddef>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+// list_node_traits can be used with list_algorithms and supplies\r
+// a list_node holding the pointers needed for a double-linked list\r
+// it is used by ilist_derived_node and ilist_member_node\r
+template<class VoidPointer>\r
+struct list_node_traits\r
+{\r
+ struct node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+\r
+ struct node\r
+ {\r
+ node_ptr prev_, next_;\r
+ };\r
+\r
+ static node_ptr get_previous(const_node_ptr n)\r
+ { return n->prev_; }\r
+\r
+ static void set_previous(node_ptr n, node_ptr prev)\r
+ { n->prev_ = prev; }\r
+\r
+ static node_ptr get_next(const_node_ptr n)\r
+ { return n->next_; }\r
+\r
+ static void set_next(node_ptr n, node_ptr next)\r
+ { n->next_ = next; }\r
+};\r
+\r
+\r
+// list_iterator provides some basic functions for a \r
+// node oriented bidirectional iterator:\r
+template<class T, class Self, class NodeTraits>\r
+class list_iterator\r
+ : public std::iterator<std::bidirectional_iterator_tag, T>\r
+{\r
+ protected:\r
+ typedef typename NodeTraits::node node;\r
+ typedef typename NodeTraits::node_ptr node_ptr;\r
+ \r
+ list_iterator()\r
+ : node_ (0)\r
+ {}\r
+\r
+ explicit list_iterator(node_ptr node)\r
+ : node_ (node)\r
+ {}\r
+\r
+ node_ptr list_node() const\r
+ { return node_; }\r
+\r
+ Self &operator=(const node_ptr &node)\r
+ { node_ = node; return static_cast<Self&>(*this); }\r
+\r
+ public:\r
+ Self& operator++() \r
+ { \r
+ node_ = NodeTraits::get_next(node_); \r
+ return static_cast<Self&> (*this); \r
+ }\r
+ \r
+ Self operator++(int)\r
+ {\r
+ Self result (node_);\r
+ node_ = NodeTraits::get_next(node_);\r
+ return result;\r
+ }\r
+\r
+ Self& operator--() \r
+ { \r
+ node_ = NodeTraits::get_previous(node_); \r
+ return static_cast<Self&> (*this); \r
+ }\r
+ \r
+ Self operator--(int)\r
+ {\r
+ Self result (node_);\r
+ node_ = NodeTraits::get_previous(node_);\r
+ return result;\r
+ }\r
+\r
+ bool operator== (const Self& i) const\r
+ { return node_ == i.list_node(); }\r
+\r
+ bool operator!= (const Self& i) const\r
+ { return !operator== (i); }\r
+\r
+ private:\r
+ node_ptr node_;\r
+};\r
+\r
+} //namespace detail \r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_LIST_NODE_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006. Distributed under the Boost\r
+// Software License, Version 1.0. (See accompanying file\r
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_POINTER_TO_OTHER_HPP\r
+#define BOOST_INTRUSIVE_POINTER_TO_OTHER_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/version.hpp>\r
+\r
+#if (BOOST_VERSION < 103400)
+
+#ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED\r
+#define BOOST_POINTER_TO_OTHER_HPP_INCLUDED\r
+
+namespace boost {\r
+\r
+template<class T, class U>\r
+ struct pointer_to_other;\r
+\r
+template<class T, class U, template <class> class Sp>\r
+ struct pointer_to_other< Sp<T>, U >\r
+{\r
+ typedef Sp<U> type;\r
+};\r
+\r
+template<class T, class T2, class U,\r
+ template <class, class> class Sp>\r
+ struct pointer_to_other< Sp<T, T2>, U >\r
+{\r
+ typedef Sp<U, T2> type;\r
+};\r
+\r
+template<class T, class T2, class T3, class U,\r
+ template <class, class, class> class Sp>\r
+struct pointer_to_other< Sp<T, T2, T3>, U >\r
+{\r
+ typedef Sp<U, T2, T3> type;\r
+};\r
+\r
+template<class T, class U>\r
+struct pointer_to_other< T*, U > \r
+{\r
+ typedef U* type;\r
+};\r
+\r
+} // namespace boost\r
+\r
+#endif\r
+\r
+#else\r
+\r
+#include <boost/pointer_to_other.hpp>\r
+\r
+#endif //#ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED\r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //#ifndef BOOST_INTRUSIVE_POINTER_TO_OTHER_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006. Distributed under the Boost\r
+// Software License, Version 1.0. (See accompanying file\r
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_POINTER_TYPE_HPP\r
+#define BOOST_INTRUSIVE_POINTER_TYPE_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+struct two {char _[2];};\r
+\r
+namespace pointer_type_imp\r
+{\r
+\r
+template <class U> static two test(...);\r
+template <class U> static char test(typename U::pointer* = 0);\r
+\r
+} //namespace pointer_type_imp\r
+\r
+template <class T>\r
+struct has_pointer_type\r
+{\r
+ static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;\r
+};\r
+\r
+template <class T, class A, bool = has_pointer_type<A>::value>\r
+struct pointer_type\r
+{\r
+ typedef typename A::pointer type;\r
+};\r
+\r
+template <class T, class A>\r
+struct pointer_type<T, A, false>\r
+{\r
+ typedef T* type;\r
+};\r
+\r
+} //namespace detail\r
+} //namespace intrusive\r
+} // namespace boost\r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //#ifndef BOOST_INTRUSIVE_POINTER_TYPE_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007.\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+// The internal implementation of red-black trees is based on that of SGI STL\r
+// stl_tree.h file: \r
+//\r
+// Copyright (c) 1996,1997\r
+// Silicon Graphics Computer Systems, Inc.\r
+//\r
+// Permission to use, copy, modify, distribute and sell this software\r
+// and its documentation for any purpose is hereby granted without fee,\r
+// provided that the above copyright notice appear in all copies and\r
+// that both that copyright notice and this permission notice appear\r
+// in supporting documentation. Silicon Graphics makes no\r
+// representations about the suitability of this software for any\r
+// purpose. It is provided "as is" without express or implied warranty.\r
+//\r
+//\r
+// Copyright (c) 1994\r
+// Hewlett-Packard Company\r
+//\r
+// Permission to use, copy, modify, distribute and sell this software\r
+// and its documentation for any purpose is hereby granted without fee,\r
+// provided that the above copyright notice appear in all copies and\r
+// that both that copyright notice and this permission notice appear\r
+// in supporting documentation. Hewlett-Packard Company makes no\r
+// representations about the suitability of this software for any\r
+// purpose. It is provided "as is" without express or implied warranty.\r
+\r
+#ifndef BOOST_INTRUSIVE_RBTREE_NODE_HPP\r
+#define BOOST_INTRUSIVE_RBTREE_NODE_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <iterator>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/rbtree_algorithms.hpp>\r
+#include <boost/get_pointer.hpp>\r
+//#include <boost/interprocess/offset_ptr.hpp>\r
+#include <boost/type_traits/alignment_of.hpp>\r
+#include <cstddef>\r
+#include <boost/detail/no_exceptions_support.hpp>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// //\r
+// Generic node_traits for any pointer type //\r
+// //\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+//This is the default implementation, 3 generic pointers plus an enum\r
+template<class VoidPointer>\r
+struct default_rbtree_node_traits_impl\r
+{\r
+ struct node;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+\r
+ struct node\r
+ {\r
+ enum color { red_t, black_t };\r
+\r
+ static color black()\r
+ { return black_t; }\r
+\r
+ static color red()\r
+ { return red_t; }\r
+\r
+ node_ptr parent_, left_, right_;\r
+ color color_;\r
+ };\r
+\r
+ typedef typename node::color color;\r
+\r
+ static node_ptr get_parent(const_node_ptr n)\r
+ { return n->parent_; }\r
+\r
+ static void set_parent(node_ptr n, node_ptr p)\r
+ { n->parent_ = p; }\r
+\r
+ static node_ptr get_left(const_node_ptr n)\r
+ { return n->left_; }\r
+\r
+ static void set_left(node_ptr n, node_ptr l)\r
+ { n->left_ = l; }\r
+\r
+ static node_ptr get_right(const_node_ptr n)\r
+ { return n->right_; }\r
+\r
+ static void set_right(node_ptr n, node_ptr r)\r
+ { n->right_ = r; }\r
+\r
+ static color get_color(const_node_ptr n)\r
+ { return n->color_; }\r
+\r
+ static void set_color(node_ptr n, color c)\r
+ { n->color_ = c; }\r
+\r
+ static color black()\r
+ { return node::black_t; }\r
+\r
+ static color red()\r
+ { return node::red_t; }\r
+};\r
+\r
+//The default possibility is the generic implementation\r
+template<class VoidPointer>\r
+struct rbtree_node_traits\r
+ : public default_rbtree_node_traits_impl<VoidPointer>\r
+{};\r
+\r
+//This is the compact representation: 3 pointers\r
+template<class VoidPointer>\r
+struct compact_node\r
+{\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, compact_node>::type node_ptr; \r
+\r
+ enum color { red_t, black_t };\r
+\r
+ static color black()\r
+ { return black_t; }\r
+\r
+ static color red()\r
+ { return red_t; }\r
+\r
+ node_ptr parent_, left_, right_;\r
+};\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// //\r
+// Generic node_traits specialization for raw pointers //\r
+// //\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+//This specialization, embeds the color in the parent pointer\r
+//so we save one word per node\r
+template <bool TwoByteAlignment>\r
+struct rbtree_node_traits_void_ptr\r
+{\r
+ typedef compact_node<void*> node;\r
+ typedef node * node_ptr;\r
+ typedef const node * const_node_ptr;\r
+ typedef node::color color;\r
+\r
+ static node_ptr get_parent(const_node_ptr n)\r
+ { return (node_ptr)((std::size_t)n->parent_ & ~1); }\r
+\r
+ static void set_parent(node_ptr n, node_ptr p)\r
+ { n->parent_ = (node_ptr)((std::size_t)p | ((std::size_t)n->parent_ & 1)); }\r
+\r
+ static node_ptr get_left(const_node_ptr n)\r
+ { return n->left_; }\r
+\r
+ static void set_left(node_ptr n, node_ptr l)\r
+ { n->left_ = l; }\r
+\r
+ static node_ptr get_right(const_node_ptr n)\r
+ { return n->right_; }\r
+\r
+ static void set_right(node_ptr n, node_ptr r)\r
+ { n->right_ = r; }\r
+\r
+ static color get_color(const_node_ptr n)\r
+ { return (color)((std::size_t)n->parent_ & 1); }\r
+\r
+ static void set_color(node_ptr n, color c)\r
+ { n->parent_ = (node_ptr)((std::size_t)get_parent(n) | (std::size_t)c); }\r
+\r
+ static color black()\r
+ { return node::black_t; }\r
+\r
+ static color red()\r
+ { return node::red_t; }\r
+};\r
+\r
+template<>\r
+struct rbtree_node_traits_void_ptr<false>\r
+ : public default_rbtree_node_traits_impl<void*>\r
+{};\r
+\r
+//This specialization will check if the pointer optimization is\r
+//possible with raw pointers\r
+template<>\r
+struct rbtree_node_traits<void*>\r
+ : public rbtree_node_traits_void_ptr\r
+ <((boost::alignment_of< compact_node<void*> >::value % 2) == 0)>\r
+{};\r
+/*\r
+/////////////////////////////////////////////////////////////////////////////\r
+// //\r
+// Generic node_traits specialization for offset_ptr pointers //\r
+// //\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+//This specialization, embeds the color in the parent pointer\r
+//so we save one word per node.\r
+//offset_ptr, uses the offset between the pointer and the pointee\r
+//as an internal member. The 1 byte offset is defined as a null pointer\r
+//so, unlike raw pointers, so if nodes are aligned to 4 bytes,\r
+//we will use the second bit as the color mark.\r
+template <bool FourByteAlignment>\r
+struct rbtree_node_traits_offset_ptr_void\r
+{\r
+ typedef compact_node<boost::interprocess::offset_ptr<void> > node;\r
+\r
+ private:\r
+ typedef boost::interprocess::offset_ptr<node> node_ptr;\r
+ typedef boost::interprocess::offset_ptr<const node> const_node_ptr;\r
+\r
+ public:\r
+\r
+ typedef node::color color;\r
+\r
+ static node_ptr get_parent(const_node_ptr n)\r
+ { return node_ptr((node*)((std::size_t)n->parent_.get() & ~2)); }\r
+\r
+ static void set_parent(node_ptr n, node_ptr p)\r
+ {\r
+ n->parent_ = (node *)(((std::size_t)p.get()) | (((std::size_t)n->parent_.get()) & 2)); \r
+ }\r
+\r
+ static node_ptr get_left(const_node_ptr n)\r
+ { return n->left_; }\r
+\r
+ static void set_left(node_ptr n, node_ptr l)\r
+ { n->left_ = l; }\r
+\r
+ static node_ptr get_right(const_node_ptr n)\r
+ { return n->right_; }\r
+\r
+ static void set_right(node_ptr n, node_ptr r)\r
+ { n->right_ = r; }\r
+\r
+ static color get_color(const_node_ptr n)\r
+ { return (color)(((std::size_t)n->parent_.get() & 2) >> 1); }\r
+\r
+ static void set_color(node_ptr n, color c)\r
+ { n->parent_ = (node *)((std::size_t)get_parent(n).get() | ((std::size_t)c << 1)); }\r
+\r
+ static color black()\r
+ { return node::black_t; }\r
+\r
+ static color red()\r
+ { return node::red_t; }\r
+};\r
+\r
+//This is the specialization for nodes with no 4 byte alignment\r
+template <>\r
+struct rbtree_node_traits_offset_ptr_void<false>\r
+ : public default_rbtree_node_traits_impl< boost::interprocess::offset_ptr<void> >\r
+{};\r
+\r
+//This specialization will check if the pointer optimization is\r
+//possible with offset_ptr pointers\r
+template<>\r
+struct rbtree_node_traits< boost::interprocess::offset_ptr<void> >\r
+ : public rbtree_node_traits_offset_ptr_void\r
+ <((boost::alignment_of\r
+ < compact_node< boost::interprocess::offset_ptr<void> > > \r
+ ::value % 4) == 0)\r
+ >\r
+{};\r
+*/\r
+/////////////////////////////////////////////////////////////////////////////\r
+// //\r
+// A base class for the rbtree container //\r
+// //\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+// rbtree_iterator provides some basic functions for a \r
+// rb tree node oriented bidirectional iterator:\r
+template<class T, class Self, class NodeTraits>\r
+class rbtree_iterator\r
+ : public std::iterator<std::bidirectional_iterator_tag, T>\r
+{\r
+ typedef rbtree_algorithms<NodeTraits> node_algorithms;\r
+\r
+ protected:\r
+ typedef typename NodeTraits::node node;\r
+ typedef typename NodeTraits::node_ptr node_ptr;\r
+\r
+ rbtree_iterator ()\r
+ : node_ (0)\r
+ {}\r
+\r
+ explicit rbtree_iterator (node_ptr node)\r
+ : node_ (node)\r
+ {}\r
+\r
+ node_ptr tree_node() const\r
+ { return node_; }\r
+\r
+ Self &operator=(const node_ptr &node)\r
+ { node_ = node; return static_cast<Self&>(*this); }\r
+\r
+ public:\r
+ Self& operator++()\r
+ {\r
+ node_ = node_algorithms::next_node(node_);\r
+ return static_cast<Self&> (*this);\r
+ }\r
+\r
+ Self operator++(int)\r
+ {\r
+ Self result (node_);\r
+ node_ = node_algorithms::next_node (node_);\r
+ return result;\r
+ }\r
+\r
+ Self& operator--()\r
+ {\r
+ node_ = node_algorithms::prev_node (node_);\r
+ return static_cast<Self&> (*this);\r
+ }\r
+\r
+ Self operator--(int)\r
+ {\r
+ Self result (node_);\r
+ node_ = node_algorithms::prev_node (node_);\r
+ return result;\r
+ }\r
+\r
+ bool operator== (const Self& i) const\r
+ { return node_ == i.tree_node(); }\r
+\r
+ bool operator!= (const Self& i) const\r
+ { return !operator== (i); }\r
+\r
+ private:\r
+ node_ptr node_;\r
+};\r
+\r
+\r
+} //namespace detail \r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_RBTREE_NODE_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_SLIST_NODE_HPP\r
+#define BOOST_INTRUSIVE_SLIST_NODE_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <iterator>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/slist_algorithms.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <cstddef>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+// slist_node_traits can be used with slist_algorithms and supplies\r
+// a list_node holding the pointers needed for a double-linked list\r
+// it is used by islist_derived_node and islist_member_node\r
+template<class VoidPointer>\r
+struct slist_node_traits\r
+{\r
+ struct node;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+\r
+ struct node\r
+ {\r
+ node_ptr next_;\r
+ };\r
+\r
+ static node_ptr get_next(const_node_ptr n)\r
+ { return n->next_; } \r
+\r
+ static void set_next(node_ptr n, node_ptr next)\r
+ { n->next_ = next; } \r
+};\r
+\r
+\r
+// slist_iterator provides some basic functions for a \r
+// node oriented forward iterator:\r
+template<class T, class Self, class NodeTraits>\r
+class slist_iterator\r
+ : public std::iterator<std::forward_iterator_tag, T>\r
+{\r
+ protected:\r
+ typedef typename NodeTraits::node node;\r
+ typedef typename NodeTraits::node_ptr node_ptr;\r
+\r
+ slist_iterator ()\r
+ : node_ (0)\r
+ {}\r
+\r
+ explicit slist_iterator (node_ptr node)\r
+ : node_ (node)\r
+ {}\r
+\r
+ node_ptr list_node() const\r
+ { return node_; }\r
+\r
+ Self &operator=(const node_ptr &node)\r
+ { node_ = node; return static_cast<Self&>(*this); }\r
+\r
+ public:\r
+ Self& operator++() \r
+ { \r
+ node_ = NodeTraits::get_next(node_); \r
+ return static_cast<Self&> (*this); \r
+ }\r
+ \r
+ Self operator++(int)\r
+ {\r
+ Self result (node_);\r
+ node_ = NodeTraits::get_next(node_);\r
+ return result;\r
+ }\r
+\r
+ bool operator== (const Self& i) const\r
+ { return node_ == i.list_node(); }\r
+\r
+ bool operator!= (const Self& i) const\r
+ { return !operator== (i); }\r
+\r
+ private:\r
+ node_ptr node_;\r
+};\r
+\r
+} //namespace detail \r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_SLIST_NODE_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP\r
+#define BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <cstddef>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+class null_destroyer\r
+{\r
+ public:\r
+ template <class Pointer>\r
+ void operator()(Pointer)\r
+ {}\r
+};\r
+\r
+template<bool ConstantSize, class SizeType>\r
+struct size_holder\r
+{\r
+ enum { constant_time_size = ConstantSize };\r
+ typedef SizeType size_type;\r
+\r
+ SizeType get_size() const\r
+ { return size_; }\r
+\r
+ void set_size(SizeType size)\r
+ { size_ = size; }\r
+\r
+ void decrement()\r
+ { --size_; }\r
+\r
+ void increment()\r
+ { ++size_; }\r
+\r
+ SizeType size_;\r
+};\r
+\r
+template<class SizeType>\r
+struct size_holder<false, SizeType>\r
+{\r
+ enum { constant_time_size = false };\r
+ typedef SizeType size_type;\r
+\r
+ size_type get_size() const\r
+ { return 0; }\r
+\r
+ void set_size(size_type)\r
+ {}\r
+\r
+ void decrement()\r
+ {}\r
+\r
+ void increment()\r
+ {}\r
+};\r
+\r
+template<class T, class DerivationHookType, typename Tag>\r
+struct derivation_value_traits\r
+{\r
+ public:\r
+ typedef typename DerivationHookType::node_traits node_traits;\r
+ typedef T value_type;\r
+ typedef typename node_traits::node_ptr node_ptr;\r
+ typedef typename node_traits::const_node_ptr const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <node_ptr, T>::type pointer;\r
+ typedef typename boost::pointer_to_other\r
+ <node_ptr, const T>::type const_pointer;\r
+ enum { linking_policy = DerivationHookType::linking_policy };\r
+\r
+ static node_ptr to_node_ptr(value_type &value)\r
+ { return static_cast<DerivationHookType &>(value).to_node_ptr(); }\r
+\r
+ static const_node_ptr to_node_ptr(const value_type &value)\r
+ { return static_cast<const DerivationHookType &>(value).to_node_ptr(); }\r
+\r
+ static pointer to_value_ptr(node_ptr n) \r
+ { \r
+ using boost::get_pointer;\r
+ return static_cast<T*>(get_pointer(DerivationHookType::to_hook_ptr(n))); \r
+ }\r
+\r
+ static const_pointer to_value_ptr(const_node_ptr n)\r
+ { \r
+ using boost::get_pointer;\r
+ return static_cast<const T*>(get_pointer(DerivationHookType::to_hook_ptr(n))); \r
+ }\r
+};\r
+\r
+\r
+template<class T, class MemberHookType, MemberHookType T::* P>\r
+struct member_value_traits\r
+{\r
+ public:\r
+ typedef typename MemberHookType::node_traits node_traits;\r
+ typedef T value_type;\r
+ typedef typename node_traits::node_ptr node_ptr;\r
+ typedef typename node_traits::const_node_ptr const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <node_ptr, T>::type pointer;\r
+ typedef typename boost::pointer_to_other\r
+ <node_ptr, const T>::type const_pointer;\r
+ enum { linking_policy = MemberHookType::linking_policy };\r
+\r
+ public:\r
+ static node_ptr to_node_ptr(value_type &value)\r
+ {\r
+ MemberHookType* result = &(value.*P);\r
+ return result->to_node_ptr();\r
+ }\r
+\r
+ static const_node_ptr to_node_ptr(const value_type &value)\r
+ {\r
+ const MemberHookType* result = &(value.*P);\r
+ return result->to_node_ptr();\r
+ }\r
+\r
+ //Now let's be nasty. The distance between the\r
+ //start of the value_type and the internal node\r
+ //is constant. That's why a pointer to member\r
+ //is a compile-time value. Now apply it with\r
+ //a dummy value, get the offset in bytes and go\r
+ //backwards from n to the value subtracting\r
+ //the needed bytes.\r
+ static pointer to_value_ptr(node_ptr n)\r
+ {\r
+ using boost::get_pointer;\r
+ return pointer(reinterpret_cast<value_type*>\r
+ ((char*)get_pointer(n) - value_to_node_offset()));\r
+ }\r
+\r
+ static const_pointer to_value_ptr(const_node_ptr n)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_pointer(reinterpret_cast<const value_type*>\r
+ ((const char*)get_pointer(n) - value_to_node_offset()));\r
+ }\r
+ private:\r
+ static std::size_t value_to_node_offset()\r
+ {\r
+ using boost::get_pointer;\r
+ const typename node_traits::node *np =\r
+ get_pointer((((const value_type *)0)->*P).to_node_ptr());\r
+ return ((const char*)np - (const char*)(const value_type *)0);\r
+ }\r
+};\r
+\r
+} //namespace detail \r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_ILIST_HPP\r
+#define BOOST_INTRUSIVE_ILIST_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/utility.hpp>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/ilist_hook.hpp>\r
+#include <boost/intrusive/list_algorithms.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <iterator>\r
+#include <algorithm>\r
+#include <stdexcept>\r
+#include <functional>\r
+#include <cstddef>\r
+#include <iterator>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! The class template ilist is an intrusive container that mimics most of the \r
+//! interface of std::list as described in the C++ standard.\r
+//!\r
+//! The template parameter ValueTraits is called "value traits". It stores\r
+//! information and operations about the type to be stored in the container.\r
+//!\r
+//! If the user specifies ConstantTimeSize as "true", a member of type SizeType\r
+//! will be embedded in the class, that will keep track of the number of stored objects.\r
+//! This will allow constant-time O(1) size() member, instead of default O(N) size.\r
+template< class ValueTraits\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t>\r
+class ilist\r
+ : private detail::size_holder<ConstantTimeSize, SizeType>\r
+{\r
+ private:\r
+\r
+ typedef ilist<ValueTraits, ConstantTimeSize, SizeType> this_type; \r
+ typedef typename ValueTraits::node_traits node_traits;\r
+ typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;\r
+\r
+ //! This class is\r
+ //! non-copyable\r
+ ilist (const ilist&);\r
+\r
+ //! This class is\r
+ //! non-assignable\r
+ ilist &operator =(const ilist&);\r
+\r
+ //Public typedefs\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits\r
+ <pointer>::difference_type difference_type;\r
+\r
+ //!The bidirectional iterator\r
+ class iterator;\r
+\r
+ //!The bidirectional const_iterator\r
+ class const_iterator;\r
+\r
+ //!The bidirectional iterator\r
+ friend class iterator;\r
+\r
+ //!The bidirectional const_iterator\r
+ friend class const_iterator;\r
+\r
+ private:\r
+\r
+ typedef typename node_traits::node node;\r
+ typedef typename node_traits::node_ptr node_ptr;\r
+ typedef typename node_traits::const_node_ptr const_node_ptr;\r
+ typedef list_algorithms<node_traits> node_algorithms;\r
+ enum { safemode_or_autounlink = \r
+ (int)ValueTraits::linking_policy == (int)auto_unlink ||\r
+ (int)ValueTraits::linking_policy == (int)safe_mode_link };\r
+\r
+ //Constant-time size is incompatible with auto-unlink hooks!\r
+ BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));\r
+\r
+ //This functor compares a stored value\r
+ //and the one passed as an argument\r
+ class equal_to_value\r
+ {\r
+ const value_type &t_;\r
+\r
+ public:\r
+ equal_to_value(const value_type &t)\r
+ : t_(t)\r
+ {}\r
+\r
+ bool operator()(const value_type &t)const\r
+ { return t_ == t; }\r
+ };\r
+\r
+ //Const cast emulation for smart pointers\r
+ static node_ptr uncast(const_node_ptr ptr)\r
+ {\r
+ using boost::get_pointer;\r
+ return node_ptr(const_cast<node*>(get_pointer(ptr)));\r
+ }\r
+\r
+ //This is the root node of the circular list\r
+ node root;\r
+\r
+ public:\r
+\r
+ //!The bidirectional iterator of the container\r
+ class iterator\r
+ : public detail::list_iterator<value_type, iterator, node_traits>\r
+ {\r
+ private:\r
+ // gcc warns about an ambiguity between iterator::value_type and\r
+ // ilist<ValueTraits>::value_type, thus I introduce a unique name:\r
+ typedef typename ilist<ValueTraits, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename ilist<ValueTraits, ConstantTimeSize, SizeType>::pointer private_pointer;\r
+ typedef typename ilist<ValueTraits, ConstantTimeSize, SizeType>::reference private_reference;\r
+ typedef detail::list_iterator<private_vt, iterator, node_traits> inherited;\r
+\r
+ public:\r
+ iterator()\r
+ {}\r
+\r
+ private_pointer operator->() const\r
+ { return ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ private_reference operator*() const\r
+ { return *ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ private:\r
+ explicit iterator(node_ptr node)\r
+ : inherited (node)\r
+ {}\r
+ friend class ilist<ValueTraits, ConstantTimeSize, SizeType>;\r
+ friend class detail::list_iterator<private_vt, iterator, node_traits>;\r
+ friend class const_iterator;\r
+ };\r
+\r
+ //!The bidirectional const_iterator of the container\r
+ class const_iterator\r
+ : public detail::list_iterator<const value_type, const_iterator, node_traits>\r
+ {\r
+ private:\r
+ // gcc warns about an ambiguity between const_iterator::value_type and\r
+ // ilist<ValueTraits>::value_type, thus I introduce a unique name:\r
+ typedef const typename ilist<ValueTraits, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename ilist<ValueTraits, ConstantTimeSize, SizeType>::const_pointer private_pointer;\r
+ typedef typename ilist<ValueTraits, ConstantTimeSize, SizeType>::const_reference private_reference;\r
+ typedef detail::list_iterator<private_vt, const_iterator, node_traits> inherited;\r
+ \r
+ public: \r
+ const_iterator()\r
+ {}\r
+\r
+ const_iterator(const typename ilist::iterator& it)\r
+ : inherited (it.list_node())\r
+ {}\r
+\r
+ const_iterator & operator=(const typename ilist::iterator& it)\r
+ { return inherited::operator=(it.list_node()); }\r
+\r
+ private_pointer operator->() const\r
+ { return ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ private_reference operator*() const\r
+ { return *ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ private:\r
+ explicit const_iterator(const_node_ptr node)\r
+ : inherited (uncast(node))\r
+ {}\r
+ friend class ilist<ValueTraits, ConstantTimeSize, SizeType>;\r
+ friend class detail::list_iterator<private_vt, const_iterator, node_traits>;\r
+ };\r
+\r
+ //!The bidirectional reverse iterator of the container\r
+ typedef std::reverse_iterator<iterator> reverse_iterator;\r
+\r
+ //!The bidirectional const_reverse iterator of the container\r
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: constructs an empty list. \r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks).\r
+ ilist()\r
+ { \r
+ size_traits::set_size(size_type(0));\r
+ node_algorithms::init(node_ptr(&root)); \r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Constructs a list equal to the range [first,last).\r
+ //! \r
+ //! <b>Complexity</b>: Linear in std::distance(b, e). No copy constructors are called. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks).\r
+ template<class Iterator>\r
+ ilist(Iterator b, Iterator e)\r
+ {\r
+ size_traits::set_size(size_type(0));\r
+ node_algorithms::init(node_ptr(&root));\r
+ this->insert(this->end(), b, e);\r
+ }\r
+\r
+ //! <b>Effects</b>: If it's not a safe-mode or an auto-unlink value_type \r
+ //! the destructor does nothing\r
+ //! (ie. no code is generated). Otherwise it detaches all elements from this. \r
+ //! In this case the objects in the list are not deleted (i.e. no destructors \r
+ //! are called), but the hooks according to the ValueTraits template parameter\r
+ //! are set to their default value.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the list, if \r
+ //! it's a safe-mode or auto-unlink value . Otherwise constant. \r
+ ~ilist() \r
+ {\r
+ if(safemode_or_autounlink){\r
+ this->clear(); \r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue.\r
+ //! \r
+ //! <b>Effects</b>: Inserts the value in the back of the list.\r
+ //! No copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ void push_back(value_type &value) \r
+ {\r
+ node_ptr to_insert = ValueTraits::to_node_ptr(value);\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ node_algorithms::link_before(node_ptr(&root), to_insert);\r
+ size_traits::increment();\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue.\r
+ //! \r
+ //! <b>Effects</b>: Inserts the value in the front of the list.\r
+ //! No copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ void push_front(value_type &value) \r
+ {\r
+ node_ptr to_insert = ValueTraits::to_node_ptr(value);\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ node_algorithms::link_before(node_traits::get_next(const_node_ptr(&root)), to_insert); \r
+ size_traits::increment();\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the last element of the list.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the erased element.\r
+ void pop_back() \r
+ {\r
+ node_ptr to_erase = node_traits::get_previous(const_node_ptr(&root));\r
+ node_algorithms::unlink(to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the last element of the list.\r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased element.\r
+ template<class Destroyer>\r
+ void pop_back_and_destroy(Destroyer destroyer)\r
+ {\r
+ node_ptr to_erase = node_traits::get_previous(const_node_ptr(&root));\r
+ node_algorithms::unlink(to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ destroyer(ValueTraits::to_value_ptr(to_erase));\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the first element of the list.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the erased element.\r
+ void pop_front() \r
+ { \r
+ node_ptr to_erase = node_traits::get_next(const_node_ptr(&root));\r
+ node_algorithms::unlink(to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the first element of the list.\r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased element.\r
+ template<class Destroyer>\r
+ void pop_front_and_destroy(Destroyer destroyer)\r
+ { \r
+ node_ptr to_erase = node_traits::get_next(const_node_ptr(&root));\r
+ node_algorithms::unlink(to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ destroyer(ValueTraits::to_value_ptr(to_erase));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a reference to the first element of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ reference front() \r
+ { return *ValueTraits::to_value_ptr(node_traits::get_next(const_node_ptr(&root))); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reference to the first element of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_reference front() const \r
+ { return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(const_node_ptr(&root)))); }\r
+\r
+ //! <b>Effects</b>: Returns a reference to the last element of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ reference back() \r
+ { return *ValueTraits::to_value_ptr(node_traits::get_previous(const_node_ptr(&root))); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reference to the last element of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_reference back() const \r
+ { return *ValueTraits::to_value_ptr(uncast(node_traits::get_previous(const_node_ptr(&root)))); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ iterator begin() \r
+ { return iterator(node_traits::get_next(const_node_ptr(&root))); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_iterator begin() const \r
+ { return const_iterator(node_traits::get_next(const_node_ptr(&root))); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the end of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ iterator end() \r
+ { return iterator(node_ptr(&root)); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator to the end of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_iterator end() const \r
+ { return const_iterator(const_node_ptr(&root)); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning \r
+ //! of the reversed list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ reverse_iterator rbegin()\r
+ { return reverse_iterator(end()); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning \r
+ //! of the reversed list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_reverse_iterator rbegin() const \r
+ { return const_reverse_iterator(end()); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end\r
+ //! of the reversed list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ reverse_iterator rend() \r
+ { return reverse_iterator(begin()); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end\r
+ //! of the reversed list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_reverse_iterator rend() const \r
+ { return const_reverse_iterator(begin()); }\r
+\r
+ //! <b>Effects</b>: Returns the number of the elements contained in the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements contained in the list.\r
+ //! if ConstantTimeSize is false. Constant time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ size_type size() const\r
+ {\r
+ if(ConstantTimeSize)\r
+ return size_traits::get_size();\r
+ else\r
+ return node_algorithms::count(const_node_ptr(&root)) - 1; \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns true if the list contains no elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ bool empty() const\r
+ { return node_algorithms::unique(const_node_ptr(&root)); }\r
+\r
+ //! <b>Effects</b>: Swaps the elements of x and *this.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ void swap(ilist& other)\r
+ {\r
+ node_algorithms::swap_nodes(node_ptr(&root), node_ptr(&other.root)); \r
+ if(ConstantTimeSize){\r
+ size_type backup = size_traits::get_size();\r
+ size_traits::set_size(other.get_size());\r
+ other.set_size(backup);\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed by i of the list.\r
+ //! No destructors are called.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed element,\r
+ //! or end() if no such element exists.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased element.\r
+ iterator erase(iterator i)\r
+ {\r
+ iterator erase = i;\r
+ ++i;\r
+ node_ptr to_erase = erase.list_node();\r
+ node_algorithms::unlink(to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ return i;\r
+ }\r
+\r
+ //! <b>Requires</b>: first and last must be valid iterator to elements in *this.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element range pointed by b and e\r
+ //! No destructors are called.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements erased if it's a safe-mode\r
+ //! or auto-unlink value. Constant time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the \r
+ //! erased elements.\r
+ iterator erase(iterator b, iterator e)\r
+ {\r
+ if(safemode_or_autounlink || ConstantTimeSize){\r
+ while(b != e){\r
+ b = this->erase(b);\r
+ }\r
+ return b;\r
+ }\r
+ else{\r
+ node_algorithms::unlink(b.list_node(), e.list_node());\r
+ return e;\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed by i of the list.\r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed element,\r
+ //! or end() if no such element exists.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased element.\r
+ template <class Destroyer>\r
+ iterator erase_and_destroy(iterator i, Destroyer destroyer)\r
+ {\r
+ iterator erase = i;\r
+ ++i;\r
+ node_ptr to_erase = erase.list_node();\r
+ node_algorithms::unlink(to_erase);\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ destroyer(ValueTraits::to_value_ptr(to_erase));\r
+ return i;\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element range pointed by b and e\r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements erased.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased elements.\r
+ template <class Destroyer>\r
+ iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer)\r
+ {\r
+ while(b != e){\r
+ b = this->erase_and_destroy(b, destroyer);\r
+ }\r
+ return b;\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements of the list.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the erased elements.\r
+ void clear()\r
+ {\r
+ if(safemode_or_autounlink){\r
+ this->erase(this->begin(), this->end()); \r
+ }\r
+ else{\r
+ node_algorithms::init(node_ptr(&root));\r
+ size_traits::set_size(size_type(0));\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements of the list.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased elements.\r
+ template <class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ { this->erase_and_destroy(this->begin(), this->end(), destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws. Basic guarantee.\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const ilist &src, Cloner cloner, Destroyer destroyer)\r
+ {\r
+ this->clear_and_destroy(destroyer);\r
+ try{\r
+ const_iterator b(src.begin()), e(src.end());\r
+ for(; b != e; ++b){\r
+ this->push_back(*cloner(*b));\r
+ }\r
+ }\r
+ catch(...){\r
+ clear_and_destroy(destroyer);\r
+ throw;\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and p must be a valid iterator of *this.\r
+ //!\r
+ //! <b>Effects</b>: Inserts the value before the position pointed by p.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the inserted element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time. No copy constructors are called.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ iterator insert(iterator p, value_type &value)\r
+ {\r
+ node_ptr to_insert = ValueTraits::to_node_ptr(value);\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ node_algorithms::link_before(p.list_node(), to_insert);\r
+ size_traits::increment();\r
+ return iterator(to_insert);\r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type and p must be a valid iterator of *this.\r
+ //! \r
+ //! <b>Effects</b>: Inserts the range pointed by b and e before the position p.\r
+ //! No copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ template<class Iterator>\r
+ void insert(iterator p, Iterator b, Iterator e)\r
+ {\r
+ for (; b != e; ++b)\r
+ this->insert(p, *b);\r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Clears the list and inserts the range pointed by b and e.\r
+ //! No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted plus\r
+ //! linear to the elements contained in the list if it's a safe-mode\r
+ //! or auto-unlink value.\r
+ //! Linear to the number of elements inserted in the list otherwise.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements.\r
+ template<class Iterator>\r
+ void assign(Iterator b, Iterator e)\r
+ {\r
+ this->clear();\r
+ this->insert(this->end(), b, e);\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Clears the list and inserts the range pointed by b and e.\r
+ //! No destructors or copy constructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted plus\r
+ //! linear to the elements contained in the list.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements.\r
+ template<class Iterator, class Destroyer>\r
+ void assign_and_destroy(Iterator b, Iterator e, Destroyer destroyer)\r
+ {\r
+ this->clear(destroyer);\r
+ this->insert(this->end(), b, e);\r
+ }\r
+\r
+ //! <b>Requires</b>: p must be a valid iterator of *this.\r
+ //!\r
+ //! <b>Effects</b>: Transfers all the elements of list x to this list, before the\r
+ //! the element pointed by p. No destructors or copy constructors are called.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //!\r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of\r
+ //! this list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator p, ilist& x)\r
+ {\r
+ if(!x.empty()){\r
+ node_algorithms::transfer\r
+ (p.list_node(), x.begin().list_node(), x.end().list_node());\r
+ size_traits::set_size(size_traits::get_size() + x.get_size());\r
+ x.set_size(size_type(0));\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: p must be a valid iterator of *this.\r
+ //! new_ele must point to an element contained in list x.\r
+ //! \r
+ //! <b>Effects</b>: Transfers the value pointed by new_ele, from list x to this list, \r
+ //! before the the element pointed by p. No destructors or copy constructors are called.\r
+ //! If p == new_ele or p == ++new_ele, this function is a null operation. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator p, ilist&x, iterator new_ele)\r
+ {\r
+ node_algorithms::transfer(p.list_node(), new_ele.list_node());\r
+ x.decrement();\r
+ size_traits::increment();\r
+ }\r
+\r
+ //! <b>Requires</b>: p must be a valid iterator of *this.\r
+ //! start and end must point to elements contained in list x.\r
+ //! \r
+ //! <b>Effects</b>: Transfers the range pointed by start and end from list x to this list, \r
+ //! before the the element pointed by p. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements transferred\r
+ //! if ConstantTimeSize is true. Constant-time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator p, ilist&x, iterator start, iterator end)\r
+ {\r
+ if(start != end){\r
+ if(ConstantTimeSize){\r
+ size_type increment = std::distance(start, end);\r
+ node_algorithms::transfer(p.list_node(), start.list_node(), end.list_node());\r
+ size_traits::set_size(size_traits::get_size() + increment);\r
+ x.set_size(x.get_size() - increment);\r
+ }\r
+ else{\r
+ node_algorithms::transfer(p.list_node(), start.list_node(), end.list_node());\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: p must be a valid iterator of *this.\r
+ //! start and end must point to elements contained in list x.\r
+ //! n == std::distance(start, end)\r
+ //! \r
+ //! <b>Effects</b>: Transfers the range pointed by start and end from list x to this list, \r
+ //! before the the element pointed by p. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator p, ilist&x, iterator start, iterator end, difference_type n)\r
+ {\r
+ if(n){\r
+ if(ConstantTimeSize){\r
+ BOOST_ASSERT(n == std::distance(start, end));\r
+ node_algorithms::transfer(p.list_node(), start.list_node(), end.list_node());\r
+ size_traits::set_size(size_traits::get_size() + n);\r
+ x.set_size(x.get_size() - n);\r
+ }\r
+ else{\r
+ node_algorithms::transfer(p.list_node(), start.list_node(), end.list_node());\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>. \r
+ //! The sort is stable, that is, the relative order of equivalent elements is preserved.\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or std::less<value_type> throws. Basic guarantee.\r
+ //!\r
+ //! <b>Notes</b>: Iterators and references are not invalidated.\r
+ //! \r
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N\r
+ //! is the list's size.\r
+ void sort() \r
+ { sort(std::less<value_type>()); }\r
+\r
+ //! <b>Requires</b>: p must be a comparison function that induces a strict weak ordering\r
+ //! \r
+ //! <b>Effects</b>: This function sorts the list *this according to p. The sort is \r
+ //! stable, that is, the relative order of equivalent elements is preserved.\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the predicate throws. Basic guarantee.\r
+ //!\r
+ //! <b>Notes</b>: This won't throw if ilist_base_hook<>::value_traits or\r
+ //! ilist_member_hook::::value_traits are used as value traits.\r
+ //! Iterators and references are not invalidated.\r
+ //! \r
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N\r
+ //! is the list's size.\r
+ template<class Predicate>\r
+ void sort(Predicate p)\r
+ {\r
+ if(node_traits::get_next(const_node_ptr(&root)) \r
+ != node_traits::get_previous(const_node_ptr(&root))){\r
+ ilist carry;\r
+ ilist counter[64];\r
+ int fill = 0;\r
+ while(!this->empty()){\r
+ carry.splice(carry.begin(), *this, this->begin());\r
+ int i = 0;\r
+ while(i < fill && !counter[i].empty()) {\r
+ carry.merge(counter[i++], p);\r
+ }\r
+ carry.swap(counter[i]);\r
+ if(i == fill)\r
+ ++fill;\r
+ }\r
+ for (int i = 1; i < fill; ++i)\r
+ counter[i].merge(counter[i-1], p);\r
+ this->swap(counter[fill-1]);\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them\r
+ //! in order into *this according to std::less<value_type>. The merge is stable; \r
+ //! that is, if an element from *this is equivalent to one from x, then the element \r
+ //! from *this will precede the one from x. \r
+ //! \r
+ //! <b>Throws</b>: If std::less<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time: it performs at most\r
+ //! size() + x.size() - 1 comparisons.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated\r
+ void merge(ilist& x)\r
+ { merge(x, std::less<value_type>()); }\r
+\r
+ //! <b>Requires</b>: p must be a comparison function that induces a strict weak\r
+ //! ordering and both *this and x must be sorted according to that ordering\r
+ //! The lists x and *this must be distinct. \r
+ //! \r
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them\r
+ //! in order into *this. The merge is stable; that is, if an element from *this is \r
+ //! equivalent to one from x, then the element from *this will precede the one from x. \r
+ //! \r
+ //! <b>Throws</b>: If the predicate throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time: it performs at most\r
+ //! size() + x.size() - 1 comparisons.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ template<class Predicate>\r
+ void merge(ilist& x, Predicate p)\r
+ {\r
+ iterator e = this->end();\r
+ iterator bx = x.begin();\r
+ iterator ex = x.end();\r
+\r
+ for (iterator b = this->begin(); b != e; ++b) {\r
+ size_type n(0);\r
+ iterator ix(bx);\r
+ while(ix != ex && p(*ix, *b)){\r
+ ++ix; ++n;\r
+ }\r
+ this->splice(b, x, bx, ix, n);\r
+ bx = ix;\r
+ }\r
+ //Now transfer the rest at the end of the container\r
+ this->splice(e, x);\r
+ }\r
+\r
+ //! <b>Effects</b>: Reverses the order of elements in the list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated\r
+ void reverse()\r
+ { node_algorithms::reverse(node_ptr(&root)); }\r
+\r
+ //! <b>Effects</b>: Removes all the elements that compare equal to value.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If std::equal_to<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ void remove(const value_type &value)\r
+ { remove_if(equal_to_value(value)); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes all the elements that compare equal to value.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //!\r
+ //! <b>Throws</b>: If std::equal_to<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Destroyer>\r
+ void remove_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { remove_and_destroy_if(equal_to_value(value), destroyer); }\r
+\r
+ //! <b>Effects</b>: Removes all the elements for which a specified\r
+ //! predicate is satisfied. No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If pred throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() calls to the predicate.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Pred>\r
+ void remove_if(Pred pred)\r
+ { remove_and_destroy_if(pred, detail::null_destroyer()); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes all the elements for which a specified\r
+ //! predicate is satisfied.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //!\r
+ //! <b>Throws</b>: If pred throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.\r
+ //!\r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Pred, class Destroyer>\r
+ void remove_and_destroy_if(Pred pred, Destroyer destroyer)\r
+ {\r
+ iterator first = begin();\r
+ iterator last = end();\r
+ while(first != last) {\r
+ iterator next = first;\r
+ ++next;\r
+ if(pred(*first)){\r
+ pointer p = first.operator->();\r
+ this->erase(first);\r
+ destroyer(p);\r
+ }\r
+ first = next;\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that are equal from the list. No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If std::equal_to<value_type throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1 comparisons calls to pred()).\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ void unique()\r
+ { unique_and_destroy(std::equal_to<value_type>(), detail::null_destroyer()); }\r
+\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that satisfy some binary predicate from the list.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If pred throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1 comparisons equality comparisons).\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class BinaryPredicate>\r
+ void unique(BinaryPredicate pred)\r
+ { unique_and_destroy(pred, detail::null_destroyer()); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that are equal from the list.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //! \r
+ //! <b>Throws</b>: If std::equal_to<value_type throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1) comparisons equality comparisons.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Destroyer>\r
+ void unique_and_destroy(Destroyer destroyer)\r
+ { unique_and_destroy(std::equal_to<value_type>(), destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that satisfy some binary predicate from the list.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //! \r
+ //! <b>Throws</b>: If pred throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1) comparisons equality comparisons.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class BinaryPredicate, class Destroyer>\r
+ void unique_and_destroy(BinaryPredicate pred, Destroyer destroyer)\r
+ {\r
+ if(!this->empty()){\r
+ iterator first = begin();\r
+ iterator after = first;\r
+ ++after;\r
+ while(after != this->end()){\r
+ if(pred(*first, *after)){\r
+ pointer p = after.operator->();\r
+ after = erase(after);\r
+ destroyer(p);\r
+ }\r
+ else{\r
+ first = after++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be a reference to a value inserted in a list.\r
+ //! \r
+ //! <b>Effects</b>: This function returns a const_iterator pointing to the element\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ static iterator current(value_type &value)\r
+ { \r
+ BOOST_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(value)));\r
+ return iterator(ValueTraits::to_node_ptr(value)); \r
+ }\r
+\r
+ //! <b>Requires</b>: value must be a const reference to a value inserted in a list.\r
+ //! \r
+ //! <b>Effects</b>: This function returns an iterator pointing to the element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ static const_iterator current(const value_type &value) \r
+ { \r
+ BOOST_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast<value_type&> (value))));\r
+ return const_iterator(ValueTraits::to_node_ptr(const_cast<value_type&> (value))); \r
+ }\r
+};\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator==(const ilist<V, C, S>& x, const ilist<V, C, S>& y)\r
+{\r
+ if(C && x.size() != y.size()){\r
+ return false;\r
+ }\r
+ typedef typename ilist<V, C, S>::const_iterator const_iterator;\r
+ const_iterator end1 = x.end();\r
+\r
+ const_iterator i1 = x.begin();\r
+ const_iterator i2 = y.begin();\r
+ if(C){\r
+ while (i1 != end1 && *i1 == *i2) {\r
+ ++i1;\r
+ ++i2;\r
+ }\r
+ return i1 == end1;\r
+ }\r
+ else{\r
+ const_iterator end2 = y.end();\r
+ while (i1 != end1 && i2 != end2 && *i1 == *i2) {\r
+ ++i1;\r
+ ++i2;\r
+ }\r
+ return i1 == end1 && i2 == end2;\r
+ }\r
+}\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator<(const ilist<V, C, S>& x,\r
+ const ilist<V, C, S>& y)\r
+{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator!=(const ilist<V, C, S>& x, const ilist<V, C, S>& y) \r
+{ return !(x == y); }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator>(const ilist<V, C, S>& x, const ilist<V, C, S>& y) \r
+{ return y < x; }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator<=(const ilist<V, C, S>& x, const ilist<V, C, S>& y) \r
+{ return !(y < x); }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator>=(const ilist<V, C, S>& x, const ilist<V, C, S>& y) \r
+{ return !(x < y); }\r
+\r
+template <class V, bool C, class S>\r
+inline void swap(ilist<V, C, S>& x, ilist<V, C, S>& y)\r
+{ x.swap(y); }\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_ILIST_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_ILIST_HOOK_HPP\r
+#define BOOST_INTRUSIVE_ILIST_HOOK_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/utilities.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/detail/list_node.hpp>\r
+#include <boost/intrusive/list_algorithms.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <stdexcept>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! Derive a class from ilist_base_hook in order to store objects in \r
+//! in an ilist. ilist_base_hook holds the data necessary to maintain the \r
+//! list and provides an appropriate value_traits class for ilist.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one ilist_base_hook, then each ilist_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the ilist configured from this hook.\r
+template< typename Tag\r
+ , bool SafeMode = true\r
+ , class VoidPointer = void *\r
+ >\r
+class ilist_base_hook\r
+ : private detail::list_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::list_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = SafeMode ? safe_mode_link : normal_link};\r
+\r
+ private:\r
+ typedef list_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef ilist_base_hook\r
+ <Tag, SafeMode, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ilist_base_hook()\r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using ilist_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ ilist_base_hook(const ilist_base_hook& ) \r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using ilist_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ ilist_base_hook& operator=(const ilist_base_hook& ) \r
+ {\r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ return *this; \r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an ilist an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~ilist_base_hook() \r
+ { \r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing. \r
+ void swap_nodes(ilist_base_hook &other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Precondition</b>: The hook must be in safe-mode.\r
+ //!\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether ilist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ {\r
+ //linked() can be only used in safe-mode\r
+ BOOST_ASSERT(SafeMode);\r
+ return !node_algorithms::unique(this_as_node()); \r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for ilist. \r
+ //! The template argument T defines the class type stored in ilist. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<ilist_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const ilist_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+\r
+//! Derive a class from ilist_auto_base_hook in order to store objects in \r
+//! in an ilist. ilist_auto_base_hook holds the data necessary to maintain the \r
+//! list and provides an appropriate value_traits class for ilist.\r
+//!\r
+//! The difference between ilist_auto_base_hook and ilist_base_hook is that\r
+//! ilist_auto_base_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! ilist_auto_base_hook can only be used with non constant-time ilists.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one ilist_auto_base_hook, then each ilist_auto_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the ilist configured from this hook.\r
+template< typename Tag\r
+ , class VoidPointer = void *\r
+ >\r
+class ilist_auto_base_hook\r
+ : private detail::list_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::list_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = auto_unlink };\r
+\r
+ private:\r
+ typedef list_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef ilist_auto_base_hook\r
+ <Tag, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ilist_auto_base_hook()\r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using ilist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ ilist_auto_base_hook(const ilist_auto_base_hook& ) \r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using ilist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ ilist_auto_base_hook& operator=(const ilist_auto_base_hook& ) \r
+ { this->unlink(); return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~ilist_auto_base_hook() \r
+ { this->unlink(); }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing. \r
+ void swap_nodes(ilist_auto_base_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether ilist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return !node_algorithms::unique(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ {\r
+ node_algorithms::unlink(this_as_node());\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for ilist. \r
+ //! The template argument T defines the class type stored in ilist. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<ilist_auto_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const ilist_auto_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+//! Put a public data member ilist_member_hook in order to store objects of this class in\r
+//! an ilist. ilist_member_hook holds the data necessary for maintaining the list and \r
+//! provides an appropriate value_traits class for ilist.\r
+//! \r
+//! The template argument T defines the class type stored in ilist. Objects of type \r
+//! T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//! \r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the ilist configured from this hook.\r
+template<class T, bool SafeMode = true, class VoidPointer = void *>\r
+class ilist_member_hook\r
+ : private detail::list_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::list_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+\r
+ private:\r
+ typedef list_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef ilist_member_hook\r
+ <T, SafeMode, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type >::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type >::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ilist_member_hook()\r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using ilist_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ ilist_member_hook(const ilist_member_hook& ) \r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using ilist_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ ilist_member_hook& operator=(const ilist_member_hook& )\r
+ {\r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ return *this;\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an ilist an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~ilist_member_hook()\r
+ {\r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ void swap_nodes(ilist_member_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Precondition</b>: The hook must be in safe-mode.\r
+ //!\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether ilist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant\r
+ bool linked() const \r
+ {\r
+ //We must be in safe-mode to know if we are really linked\r
+ //Otherwise, this would lead to an unknown state\r
+ BOOST_ASSERT(SafeMode);\r
+ return !node_algorithms::unique(this_as_node());\r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for ilist. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+//! Put a public data member ilist_auto_member_hook in order to store objects of this class in\r
+//! an ilist. ilist_auto_member_hook holds the data necessary for maintaining the list and \r
+//! provides an appropriate value_traits class for ilist.\r
+//!\r
+//! The difference between ilist_auto_member_hook and ilist_member_hook is that\r
+//! ilist_auto_member_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! ilist_auto_member_hook can only be used with non constant-time ilists.\r
+//! \r
+//! The first template argument T defines the class type stored in ilist. Objects of\r
+//! type T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the ilist configured from this hook.\r
+template<class T, class VoidPointer = void *>\r
+class ilist_auto_member_hook\r
+ : private detail::list_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::list_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = auto_unlink };\r
+\r
+ private:\r
+ typedef list_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef ilist_auto_member_hook\r
+ <T, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type >::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type >::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ilist_auto_member_hook()\r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using ilist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ ilist_auto_member_hook(const ilist_auto_member_hook& ) \r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using ilist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ ilist_auto_member_hook& operator=(const ilist_auto_member_hook& )\r
+ { this->unlink(); return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~ilist_auto_member_hook()\r
+ { this->unlink(); }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ void swap_nodes(ilist_auto_member_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether ilist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return !node_algorithms::unique(this_as_node()); }\r
+\r
+ //! The value_traits class is used as the first template argument for ilist. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ {\r
+ node_algorithms::unlink(this_as_node());\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_ILIST_HOOK_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#ifndef BOOST_INTRUSIVE_ISET_HPP\r
+#define BOOST_INTRUSIVE_ISET_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/irbtree.hpp>\r
+#include <iterator>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! The class template iset is an intrusive container, that mimics most of \r
+//! the interface of std::set as described in the C++ standard.\r
+//! \r
+//! The template parameter ValueTraits is called "value traits". It stores\r
+//! information and operations about the type to be stored in the container.\r
+//!\r
+//! The template parameter Compare, provides a function object that can compare two \r
+//! element values as sort keys to determine their relative order in the set. \r
+//!\r
+//! If the user specifies ConstantTimeSize as "true", a member of type SizeType\r
+//! will be embedded in the class, that will keep track of the number of stored objects.\r
+//! This will allow constant-time O(1) size() member, instead of default O(N) size.\r
+template < class ValueTraits\r
+ , class Compare = std::less<typename ValueTraits::value_type>\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t>\r
+class iset\r
+{\r
+ typedef detail::irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType> tree_type;\r
+\r
+ //! This class is\r
+ //! non-copyable\r
+ iset (const iset&);\r
+\r
+ //! This class is\r
+ //! non-assignable\r
+ iset &operator =(const iset&);\r
+\r
+ typedef tree_type implementation_defined;\r
+\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits\r
+ <pointer>::difference_type difference_type;\r
+ typedef value_type key_type;\r
+ typedef Compare value_compare;\r
+ typedef value_compare key_compare;\r
+ typedef typename implementation_defined::iterator iterator;\r
+ typedef typename implementation_defined::const_iterator const_iterator;\r
+ typedef typename implementation_defined::reverse_iterator reverse_iterator;\r
+ typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator;\r
+ typedef typename implementation_defined::insert_commit_data insert_commit_data;\r
+\r
+ private:\r
+ tree_type tree_;\r
+\r
+ template <class V1, class P1, bool C1, class S1>\r
+ friend bool operator==(const iset<V1, P1, C1, S1>& x, const iset<V1, P1, C1, S1>& y);\r
+\r
+ template <class V1, class P1, bool C1, class S1>\r
+ friend bool operator<(const iset<V1, P1, C1, S1>& x, const iset<V1, P1, C1, S1>& y);\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: Constructs an empty set. \r
+ //! \r
+ //! <b>Complexity</b>: Constant. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor of the Compare object throws. \r
+ iset(const Compare &cmp = Compare()) \r
+ : tree_(cmp)\r
+ {}\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type. \r
+ //! cmp must be a comparison function that induces a strict weak ordering.\r
+ //! \r
+ //! <b>Effects</b>: Constructs an empty set and inserts elements from \r
+ //! [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using \r
+ //! comp and otherwise N * log N, where N is std::distance(last, first).\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor/operator() of the Compare object throws. \r
+ template<class Iterator>\r
+ iset(Iterator b, Iterator e, const Compare &cmp = Compare())\r
+ : tree_(true, b, e, cmp)\r
+ { insert(b, e); }\r
+\r
+ //! <b>Effects</b>: Detaches all elements from this. The objects in the set \r
+ //! are not deleted (i.e. no destructors are called).\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size()) + size()) if it's a safe-mode or auto-unlink\r
+ //! value. Otherwise constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~iset() \r
+ {}\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the beginning of the set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator begin()\r
+ { return tree_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the beginning of the set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator begin() const\r
+ { return tree_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the end of the set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator end()\r
+ { return tree_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the end of the set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator end() const\r
+ { return tree_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning of the\r
+ //! reversed set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ reverse_iterator rbegin()\r
+ { return tree_.rbegin(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning\r
+ //! of the reversed set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_reverse_iterator rbegin() const\r
+ { return tree_.rbegin(); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end\r
+ //! of the reversed set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ reverse_iterator rend()\r
+ { return tree_.rend(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end\r
+ //! of the reversed set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_reverse_iterator rend() const\r
+ { return tree_.rend(); }\r
+\r
+ //! <b>Effects</b>: Returns the key_compare object used by the set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If key_compare copy-constructor throws.\r
+ key_compare key_comp() const\r
+ { return tree_.value_comp(); }\r
+\r
+ //! <b>Effects</b>: Returns the value_compare object used by the set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If value_compare copy-constructor throws.\r
+ value_compare value_comp() const\r
+ { return tree_.value_comp(); }\r
+\r
+ //! <b>Effects</b>: Returns true is the container is empty.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bool empty() const\r
+ { return tree_.empty(); }\r
+\r
+ //! <b>Effects</b>: Returns the number of elements stored in the set.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to elements contained in *this if,\r
+ //! ConstantTimeSize is false. Constant-time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type size() const\r
+ { return tree_.size(); }\r
+\r
+ //! <b>Effects</b>: Swaps the contents of two sets.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the swap() call for the comparison functor\r
+ //! found using ADL throws. Strong guarantee.\r
+ void swap(iset& other)\r
+ { tree_.swap(other.tree_); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws.\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const iset &src, Cloner cloner, Destroyer destroyer)\r
+ { tree_.clone_from(src.tree_, cloner, destroyer); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Tries to inserts value into the set.\r
+ //!\r
+ //! <b>Returns</b>: If the value\r
+ //! is not already present inserts it and returns a pair containing the\r
+ //! iterator to the new value and true. If the value is already present\r
+ //! returns a pair containing an iterator to the already present value\r
+ //! and false.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ std::pair<iterator, bool> insert(value_type &value)\r
+ { return tree_.insert_unique(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Tries to to insert x into the set, using "hint" \r
+ //! as a hint to where it will be inserted.\r
+ //!\r
+ //! <b>Returns</b>: An iterator that points to the position where the \r
+ //! new element was inserted into the set.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic in general, but it's amortized\r
+ //! constant time if t is inserted immediately before hint.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert(const_iterator hint, value_type &value)\r
+ { return tree_.insert_unique(hint, value); }\r
+\r
+ //! <b>Requires</b>: key_value_comp must be a comparison function that induces \r
+ //! the same strict weak ordering as value_compare. The difference is that\r
+ //! key_value_comp compares an arbitrary key with the contained values.\r
+ //! \r
+ //! <b>Effects</b>: Checks if a value can be inserted in the set, using\r
+ //! a user provided key instead of the value itself.\r
+ //!\r
+ //! <b>Returns</b>: If an equivalent value is already present\r
+ //! returns a pair containing an iterator to the already present value\r
+ //! and false. If the value can be inserted returns true in the returned\r
+ //! pair boolean and fills "commit_data" that is meant to be used with\r
+ //! the "insert_commit" function.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is at most logarithmic.\r
+ //!\r
+ //! <b>Throws</b>: If the key_value_comp ordering function throws. Strong guarantee.\r
+ //! \r
+ //! <b>Notes</b>: This function is used to improve performance when constructing\r
+ //! a value_type is expensive: if an equivalent value is already present\r
+ //! the constructed object must be discarded. Many times, the part of the\r
+ //! node that is used to impose the order is much cheaper to construct\r
+ //! than the value_type and this function offers the possibility to use that \r
+ //! part to check if the insertion will be successful.\r
+ //!\r
+ //! If the check is successful, the user can construct the value_type and use\r
+ //! "insert_commit" to insert the object in constant-time. This gives a total\r
+ //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).\r
+ //!\r
+ //! "commit_data" remains valid for a subsequent "insert_commit" only if no more\r
+ //! objects are inserted or erased from the set.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator, bool> insert_check\r
+ (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data)\r
+ { return tree_.insert_unique_check(key, key_value_comp, commit_data); }\r
+\r
+ //! <b>Requires</b>: key_value_comp must be a comparison function that induces \r
+ //! the same strict weak ordering as value_compare. The difference is that\r
+ //! key_value_comp compares an arbitrary key with the contained values.\r
+ //! \r
+ //! <b>Effects</b>: Checks if a value can be inserted in the set, using\r
+ //! a user provided key instead of the value itself, using "hint" \r
+ //! as a hint to where it will be inserted.\r
+ //!\r
+ //! <b>Returns</b>: If an equivalent value is already present\r
+ //! returns a pair containing an iterator to the already present value\r
+ //! and false. If the value can be inserted returns true in the returned\r
+ //! pair boolean and fills "commit_data" that is meant to be used with\r
+ //! the "insert_commit" function.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic in general, but it's amortized\r
+ //! constant time if t is inserted immediately before hint.\r
+ //!\r
+ //! <b>Throws</b>: If the key_value_comp ordering function throws. Strong guarantee.\r
+ //! \r
+ //! <b>Notes</b>: This function is used to improve performance when constructing\r
+ //! a value_type is expensive: if the equivalent is already present\r
+ //! the constructed object must be discarded. Many times, the part of the\r
+ //! constructing that is used to impose the order is much cheaper to construct\r
+ //! than the value_type and this function offers the possibility to use that key \r
+ //! to check if the insertion will be successful.\r
+ //!\r
+ //! If the check is successful, the user can construct the value_type and use\r
+ //! "insert_commit" to insert the object in constant-time. This can give a total\r
+ //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)).\r
+ //! \r
+ //! "commit_data" remains valid for a subsequent "insert_commit" only if no more\r
+ //! objects are inserted or erased from the set.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator, bool> insert_check\r
+ (const_iterator hint, const KeyType &key\r
+ ,KeyValueCompare key_value_comp, insert_commit_data &commit_data)\r
+ { return tree_.insert_unique_check(hint, key, key_value_comp, commit_data); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue of type value_type. commit_data\r
+ //! must have been obtained from a previous call to "insert_check".\r
+ //! No objects should have been inserted or erased from the set between\r
+ //! the "insert_check" that filled "commit_data" and the call to "insert_commit".\r
+ //! \r
+ //! <b>Effects</b>: Inserts the value in the set using the information obtained\r
+ //! from the "commit_data" that a previous "insert_check" filled.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the newly inserted object.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Notes</b>: This function has only sense if a "insert_check" has been\r
+ //! previously executed to fill "commit_data". No value should be inserted or\r
+ //! erased between the "insert_check" and "insert_commit" calls.\r
+ iterator insert_commit(value_type &value, const insert_commit_data &commit_data)\r
+ { return tree_.insert_unique_commit(value, commit_data); }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue \r
+ //! of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Inserts a range into the set.\r
+ //! \r
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the \r
+ //! size of the range. However, it is linear in N if the range is already sorted \r
+ //! by value_comp().\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ template<class Iterator>\r
+ void insert(Iterator b, Iterator e)\r
+ { tree_.insert_unique(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed to by pos. \r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is constant time.\r
+ //! \r
+ //! <b>Returns</b>: An iterator to the element after the erased element.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ iterator erase(iterator i)\r
+ { return tree_.erase(i); }\r
+\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e. \r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase range is at most \r
+ //! O(log(size() + N)), where N is the number of elements in the range.\r
+ //! \r
+ //! <b>Returns</b>: An iterator to the element after the erased elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ iterator erase(iterator b, iterator e)\r
+ { return tree_.erase(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size()) + this->count(value)).\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ size_type erase(const value_type &value)\r
+ { return tree_.erase(value); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements that compare equal with\r
+ //! the given key and the given comparison functor.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(key, comp)).\r
+ //! \r
+ //! <b>Throws</b>: If the comp ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class KeyType, class KeyValueCompare>\r
+ size_type erase(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.erase(key, comp); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed to by pos. \r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase element is constant time. \r
+ //! \r
+ //! <b>Returns</b>: An iterator to the element after the erased element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators \r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator i, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(i, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase range is at most \r
+ //! O(log(size() + N)), where N is the number of elements in the range.\r
+ //! \r
+ //! <b>Returns</b>: An iterator to the element after the erased elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(b, e, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(value)). Basic guarantee.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(value, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given key.\r
+ //! according to the comparison functor "comp".\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(key, comp)).\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class KeyType, class KeyValueCompare, class Destroyer>\r
+ size_type erase_and_destroy(const KeyType& key, KeyValueCompare comp, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(key, comp, destroyer); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void clear()\r
+ { return tree_.clear(); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //! \r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ { return tree_.clear_and_destroy(destroyer); }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given key\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal\r
+ //! to number of objects with the given key.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ size_type count(const value_type &value) const\r
+ { return tree_.find(value) != end(); }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the same key\r
+ //! compared with the given comparison functor.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal\r
+ //! to number of objects with the given key.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ template<class KeyType, class KeyValueCompare>\r
+ size_type count(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.find(key, comp) != end(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ iterator lower_bound(const value_type &value)\r
+ { return tree_.lower_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key according to the comparison functor is not less than k or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //! \r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator lower_bound(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.lower_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Returns a const iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ const_iterator lower_bound(const value_type &value) const\r
+ { return tree_.lower_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_iterator to the first element whose\r
+ //! key according to the comparison functor is not less than k or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //! \r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.lower_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ iterator upper_bound(const value_type &value)\r
+ { return tree_.upper_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key according to the comparison functor is greater than key or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator upper_bound(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.upper_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ const_iterator upper_bound(const value_type &value) const\r
+ { return tree_.upper_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_iterator to the first element whose\r
+ //! key according to the comparison functor is greater than key or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.upper_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose value is \r
+ //! "value" or end() if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ iterator find(const value_type &value)\r
+ { return tree_.find(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! "key" according to the comparison functor or end() if that element \r
+ //! does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator find(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.find(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose value is \r
+ //! "value" or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ const_iterator find(const value_type &value) const\r
+ { return tree_.find(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose key is \r
+ //! "key" according to the comparison functor or end() if that element \r
+ //! does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator find(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.find(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ std::pair<iterator,iterator> equal_range(const value_type &value)\r
+ { return tree_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k \r
+ //! according to the comparison functor or an empty range \r
+ //! that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator,iterator> equal_range(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.equal_range(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const value_type &value) const\r
+ { return tree_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k \r
+ //! according to the comparison functor or an empty range \r
+ //! that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.equal_range(key, comp); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the set\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static iterator current(value_type &value)\r
+ { return tree_type::current(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the\r
+ //! set that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_iterator current(const value_type &value)\r
+ { return tree_type::current(value); }\r
+\r
+ friend bool operator==(const iset &x, const iset &y)\r
+ { return x.tree_ == y.tree_; }\r
+\r
+ friend bool operator<(const iset &x, const iset &y)\r
+ { return x.tree_ < y.tree_; }\r
+};\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator!=(const iset<V, P, C, S>& x, const iset<V, P, C, S>& y) \r
+{ return !(x==y); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator>(const iset<V, P, C, S>& x, const iset<V, P, C, S>& y) \r
+{ return y < x; }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator<=(const iset<V, P, C, S>& x, const iset<V, P, C, S>& y) \r
+{ return !(y > x); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator>=(const iset<V, P, C, S>& x, const iset<V, P, C, S>& y) \r
+{ return !(x < y); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline void swap(iset<V, P, C, S>& x, iset<V, P, C, S>& y)\r
+{ x.swap(y); }\r
+\r
+//! The class template imultiset is an intrusive container, that mimics most of \r
+//! the interface of std::multiset as described in the C++ standard.\r
+//! \r
+//! The template parameter ValueTraits is called "value traits". It stores\r
+//! information and operations about the type to be stored\r
+//! in ilist and what type of hook has been chosen to include it in the list.\r
+//! The value_traits class is supplied by the appropriate hook as a template subtype \r
+//! called "value_traits".\r
+//!\r
+//! The template parameter Compare, provides a function object that can compare two \r
+//! element values as sort keys to determine their relative order in the set. \r
+//!\r
+//! If the user specifies ConstantTimeSize as "true", a member of type SizeType\r
+//! will be embedded in the class, that will keep track of the number of stored objects.\r
+//! This will allow constant-time O(1) size() member, instead of default O(N) size.\r
+template < class ValueTraits\r
+ , class Compare = std::less<typename ValueTraits::value_type>\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t>\r
+class imultiset\r
+{\r
+ typedef detail::irbtree<ValueTraits, Compare, ConstantTimeSize, SizeType> tree_type;\r
+\r
+ //! This class is\r
+ //! non-copyable\r
+ imultiset (const imultiset&);\r
+\r
+ //! This class is\r
+ //! non-asignable\r
+ imultiset &operator =(const imultiset&);\r
+\r
+ typedef tree_type implementation_defined;\r
+\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits\r
+ <pointer>::difference_type difference_type;\r
+ typedef value_type key_type;\r
+ typedef Compare value_compare;\r
+ typedef value_compare key_compare;\r
+ typedef typename implementation_defined::iterator iterator;\r
+ typedef typename implementation_defined::const_iterator const_iterator;\r
+ typedef typename implementation_defined::reverse_iterator reverse_iterator;\r
+ typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator;\r
+ typedef typename implementation_defined::insert_commit_data insert_commit_data;\r
+\r
+ private:\r
+ tree_type tree_;\r
+\r
+ public:\r
+ //! <b>Effects</b>: Constructs an empty multiset. \r
+ //! \r
+ //! <b>Complexity</b>: Constant. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor/operator() of the Compare object throws. \r
+ imultiset(const Compare &cmp = Compare()) \r
+ : tree_(cmp)\r
+ {}\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type. \r
+ //! cmp must be a comparison function that induces a strict weak ordering.\r
+ //! \r
+ //! <b>Effects</b>: Constructs an empty multiset and inserts elements from \r
+ //! [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using \r
+ //! comp and otherwise N * log N, where N is last Ā first.\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor/operator() of the Compare object throws. \r
+ template<class Iterator>\r
+ imultiset(Iterator b, Iterator e, const Compare &cmp = Compare())\r
+ : tree_(false, b, e, cmp)\r
+ {}\r
+\r
+ //! <b>Effects</b>: Detaches all elements from this. The objects in the set \r
+ //! are not deleted (i.e. no destructors are called).\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size()) + size()) if it's a safe-mode or\r
+ //! auto-unlink value. Otherwise constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~imultiset() \r
+ {}\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the beginning of the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator begin()\r
+ { return tree_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the beginning of the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator begin() const\r
+ { return tree_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the end of the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator end()\r
+ { return tree_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the end of the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator end() const\r
+ { return tree_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning of the\r
+ //! reversed multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ reverse_iterator rbegin()\r
+ { return tree_.rbegin(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning\r
+ //! of the reversed multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_reverse_iterator rbegin() const\r
+ { return tree_.rbegin(); }\r
+\r
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end\r
+ //! of the reversed multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ reverse_iterator rend()\r
+ { return tree_.rend(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end\r
+ //! of the reversed multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_reverse_iterator rend() const\r
+ { return tree_.rend(); }\r
+\r
+ //! <b>Effects</b>: Returns the key_compare object used by the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If key_compare copy-constructor throws.\r
+ key_compare key_comp() const\r
+ { return tree_.value_comp(); }\r
+\r
+ //! <b>Effects</b>: Returns the value_compare object used by the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If value_compare copy-constructor throws.\r
+ value_compare value_comp() const\r
+ { return tree_.value_comp(); }\r
+\r
+ //! <b>Effects</b>: Returns true is the container is empty.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bool empty() const\r
+ { return tree_.empty(); }\r
+\r
+ //! <b>Effects</b>: Returns the number of elements stored in the multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to elements contained in *this if,\r
+ //! ConstantTimeSize is false. Constant-time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type size() const\r
+ { return tree_.size(); }\r
+\r
+ //! <b>Effects</b>: Swaps the contents of two multisets.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the swap() call for the comparison functor\r
+ //! found using ADL throws. Strong guarantee.\r
+ void swap(imultiset& other)\r
+ { tree_.swap(other.tree_); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws. Basic guarantee.\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const imultiset &src, Cloner cloner, Destroyer destroyer)\r
+ { tree_.clone_from(src.tree_, cloner, destroyer); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Inserts value into the multiset.\r
+ //! \r
+ //! <b>Returns</b>: An iterator that points to the position where the new\r
+ //! element was inserted.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert(value_type &value)\r
+ { return tree_.insert_equal_upper_bound(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Inserts x into the multiset, using pos as a hint to\r
+ //! where it will be inserted.\r
+ //! \r
+ //! <b>Returns</b>: An iterator that points to the position where the new\r
+ //! element was inserted.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic in general, but it is amortized\r
+ //! constant time if t is inserted immediately before hint.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert(const_iterator hint, value_type &value)\r
+ { return tree_.insert_equal(hint, value); }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue \r
+ //! of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Inserts a range into the multiset.\r
+ //! \r
+ //! <b>Returns</b>: An iterator that points to the position where the new\r
+ //! element was inserted.\r
+ //! \r
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the \r
+ //! size of the range. However, it is linear in N if the range is already sorted \r
+ //! by value_comp().\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ template<class Iterator>\r
+ void insert(Iterator b, Iterator e)\r
+ { tree_.insert_equal(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed to by pos. \r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is constant time. \r
+ //! \r
+ //! <b>Returns</b>: An iterator to the element after the erased element.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ iterator erase(iterator i)\r
+ { return tree_.erase(i); }\r
+\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e. \r
+ //!\r
+ //! <b>Returns</b>: An iterator to the element after the erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase range is at most \r
+ //! O(log(size() + N)), where N is the number of elements in the range.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ iterator erase(iterator b, iterator e)\r
+ { return tree_.erase(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(value)).\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ size_type erase(const value_type &value)\r
+ { return tree_.erase(value); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements that compare equal with\r
+ //! the given key and the given comparison functor.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(key, comp)).\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class KeyType, class KeyValueCompare>\r
+ size_type erase(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.erase(key, comp); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the element after the erased element.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed to by pos. \r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase element is constant time. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators \r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator i, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(i, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the element after the erased elements.\r
+ //!\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for erase range is at most \r
+ //! O(log(size() + N)), where N is the number of elements in the range.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(b, e, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(value)).\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(value, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given key.\r
+ //! according to the comparison functor "comp".\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: O(log(size() + this->count(key, comp)).\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class KeyType, class KeyValueCompare, class Destroyer>\r
+ size_type erase_and_destroy(const KeyType& key, KeyValueCompare comp, Destroyer destroyer)\r
+ { return tree_.erase_and_destroy(key, comp, destroyer); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void clear()\r
+ { return tree_.clear(); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //! \r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ { return tree_.clear_and_destroy(destroyer); }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the same key\r
+ //! compared with the given comparison functor.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal\r
+ //! to number of objects with the given key.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ template<class KeyType, class KeyValueCompare>\r
+ size_type count(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.find(key, comp) != end(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ iterator lower_bound(const value_type &value)\r
+ { return tree_.lower_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key according to the comparison functor is not less than k or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //! \r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator lower_bound(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.lower_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Returns a const iterator to the first element whose\r
+ //! key is not less than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ const_iterator lower_bound(const value_type &value) const\r
+ { return tree_.lower_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_iterator to the first element whose\r
+ //! key according to the comparison functor is not less than k or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //! \r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.lower_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ iterator upper_bound(const value_type &value)\r
+ { return tree_.upper_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key according to the comparison functor is greater than key or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator upper_bound(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.upper_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element whose\r
+ //! key is greater than k or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ const_iterator upper_bound(const value_type &value) const\r
+ { return tree_.upper_bound(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_iterator to the first element whose\r
+ //! key according to the comparison functor is greater than key or \r
+ //! end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.upper_bound(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose value is \r
+ //! "value" or end() if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ iterator find(const value_type &value)\r
+ { return tree_.find(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! "key" according to the comparison functor or end() if that element \r
+ //! does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ iterator find(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.find(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose value is \r
+ //! "value" or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ const_iterator find(const value_type &value) const\r
+ { return tree_.find(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose key is \r
+ //! "key" according to the comparison functor or end() if that element \r
+ //! does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ const_iterator find(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.find(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ std::pair<iterator,iterator> equal_range(const value_type &value)\r
+ { return tree_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k \r
+ //! according to the comparison functor or an empty range \r
+ //! that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<iterator,iterator> equal_range(const KeyType& key, KeyValueCompare comp)\r
+ { return tree_.equal_range(key, comp); }\r
+\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k or\r
+ //! an empty range that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If the internal Compare ordering function throws.\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const value_type &value) const\r
+ { return tree_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: comp must imply the same element order as\r
+ //! value_compare. Usually key is the part of the value_type\r
+ //! that is used in the ordering functor.\r
+ //!\r
+ //! <b>Effects</b>: Finds a range containing all elements whose key is k \r
+ //! according to the comparison functor or an empty range \r
+ //! that indicates the position where those elements would be\r
+ //! if they there is no elements with key k.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If comp ordering function throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyValueCompare>\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const KeyType& key, KeyValueCompare comp) const\r
+ { return tree_.equal_range(key, comp); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the set\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static iterator current(value_type &value)\r
+ { return tree_type::current(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the\r
+ //! set that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_iterator current(const value_type &value)\r
+ { return tree_type::current(value); }\r
+\r
+ friend bool operator==(const imultiset &x, const imultiset &y)\r
+ { return x.tree_ == y.tree_; }\r
+\r
+ friend bool operator<(const imultiset &x, const imultiset &y)\r
+ { return x.tree_ < y.tree_; }\r
+};\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator!=(const imultiset<V, P, C, S>& x, const imultiset<V, P, C, S>& y) \r
+{ return !(x==y); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator>(const imultiset<V, P, C, S>& x, const imultiset<V, P, C, S>& y) \r
+{ return y < x; }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator<=(const imultiset<V, P, C, S>& x, const imultiset<V, P, C, S>& y) \r
+{ return !(y > x); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline bool operator>=(const imultiset<V, P, C, S>& x, const imultiset<V, P, C, S>& y) \r
+{ return !(x < y); }\r
+\r
+template <class V, class P, bool C, class S>\r
+inline void swap(imultiset<V, P, C, S>& x, imultiset<V, P, C, S>& y)\r
+{ x.swap(y); }\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_ISET_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_ISET_HOOK_HPP\r
+#define BOOST_INTRUSIVE_ISET_HOOK_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/utilities.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/detail/rbtree_node.hpp>\r
+#include <boost/intrusive/rbtree_algorithms.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <stdexcept>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! Derive a class from iset_base_hook in order to store objects in \r
+//! in an iset/imultiset. iset_base_hook holds the data necessary to maintain \r
+//! the set/multiset and provides an appropriate value_traits class for iset/imultiset.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one iset_base_hook, then each iset_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the iset/imultiset configured from this hook.\r
+template<typename Tag, bool SafeMode = true, class VoidPointer = void*>\r
+class iset_base_hook\r
+ : private detail::rbtree_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::rbtree_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+\r
+ private:\r
+ typedef rbtree_algorithms<node_traits> node_algorithms;\r
+ \r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iset_base_hook\r
+ <Tag, SafeMode, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ private:\r
+\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iset_base_hook()\r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iset_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ iset_base_hook(const iset_base_hook& )\r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iset_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ iset_base_hook& operator=(const iset_base_hook& ) \r
+ {\r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ return *this; \r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an iset an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iset_base_hook() \r
+ {\r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ }\r
+\r
+ //! <b>Precondition</b>: The hook must be in safe-mode.\r
+ //!\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ {\r
+ //linked() can be only used in safe-mode\r
+ BOOST_ASSERT(SafeMode);\r
+ return !node_algorithms::unique(this_as_node()); \r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for imultiset. \r
+ //! The template argument T defines the class type stored in imultiset. Objects \r
+ //! of type T and of types derived from T can be stored. T don't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<iset_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const iset_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+//! Derive a class from iset_auto_base_hook in order to store objects in an \r
+//! iset/imultiset. iset_auto_base_hook holds the data necessary to maintain the \r
+//! set and provides an appropriate value_traits class for iset/imultiset.\r
+//!\r
+//! The difference between iset_auto_base_hook and iset_base_hook is that\r
+//! iset_auto_base_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! iset_auto_base_hook can only be used with non constant-time iset/imultisets.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one iset_auto_base_hook, then each iset_auto_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the iset/multiset configured from this hook.\r
+template<typename Tag, class VoidPointer = void*>\r
+class iset_auto_base_hook\r
+ : private detail::rbtree_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::rbtree_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = auto_unlink };\r
+\r
+ private:\r
+ typedef rbtree_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iset_auto_base_hook\r
+ <Tag, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iset_auto_base_hook()\r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iset_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iset_auto_base_hook(const iset_auto_base_hook& ) \r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iset_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iset_auto_base_hook& operator=(const iset_auto_base_hook& ) \r
+ { this->unlink(); return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iset_auto_base_hook() \r
+ { this->unlink(); }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing. \r
+ void swap_nodes(iset_auto_base_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return !node_algorithms::unique(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ {\r
+ node_algorithms::unlink_and_rebalance(this_as_node());\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for iset. \r
+ //! The template argument T defines the class type stored in iset. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<iset_auto_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const iset_auto_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+\r
+//! Put a public data member iset_member_hook in order to store objects of this class in\r
+//! an iset/imultiset. iset_member_hook holds the data necessary for maintaining the\r
+//! set/multiset and provides an appropriate value_traits class for iset/imultiset.\r
+//! \r
+//! The template argument T defines the class type stored in iset/imultiset. Objects of \r
+//! type T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//! \r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the iset/imultiset configured from this hook.\r
+template<class T, bool SafeMode = true, class VoidPointer = void*>\r
+class iset_member_hook\r
+ : private detail::rbtree_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::rbtree_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+\r
+ private:\r
+ typedef rbtree_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iset_member_hook\r
+ <T, SafeMode, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type >::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type >::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iset_member_hook()\r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iset_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iset_member_hook(const iset_member_hook& )\r
+ : node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iset_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iset_member_hook& operator=(const iset_member_hook& ) \r
+ {\r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ return *this;\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). Otherwise, if the object is \r
+ //! stored in an imultiset using the appropriate node, the object is removed \r
+ //! from that imultiset.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iset_member_hook() \r
+ { \r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant\r
+ bool linked() const \r
+ {\r
+ //We must be in safe-mode to know if we are really linked\r
+ //Otherwise, this would lead to an unknown state\r
+ BOOST_ASSERT(SafeMode);\r
+ return !node_algorithms::unique(this_as_node());\r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for imultiset. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T don't need to be copy-constructible or assignable.\r
+ template<this_type T::* P>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, P>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+//! Put a public data member iset_auto_member_hook in order to store objects of this \r
+//! class in an iset/imultiset. iset_auto_member_hook holds the data necessary for\r
+//! maintaining the set/multiset and provides an appropriate value_traits class for\r
+//! iset/imultiset.\r
+//!\r
+//! The difference between iset_auto_member_hook and iset_member_hook is that\r
+//! iset_auto_member_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! iset_auto_member_hook can only be used with non constant-time iset/imultisets.\r
+//! \r
+//! The first template argument T defines the class type stored in iset/imultisets.\r
+//! Objects of type T and of types derived from T can be stored. T doesn't need to \r
+//! be copy-constructible or assignable.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the iset/imultiset configured from this hook.\r
+template<class T, class VoidPointer = void *>\r
+class iset_auto_member_hook\r
+ : private detail::rbtree_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::rbtree_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = auto_unlink };\r
+\r
+ private:\r
+ typedef rbtree_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iset_auto_member_hook\r
+ <T, VoidPointer> this_type;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type >::type this_type_ptr;\r
+\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type >::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iset_auto_member_hook()\r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iset_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iset_auto_member_hook(const iset_auto_member_hook& ) \r
+ : node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iset_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iset_auto_member_hook& operator=(const iset_auto_member_hook& )\r
+ { this->unlink(); return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iset_auto_member_hook()\r
+ { this->unlink(); }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ void swap_nodes(iset_auto_member_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return !node_algorithms::unique(this_as_node()); }\r
+\r
+ //! The value_traits class is used as the first template argument for iset. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ {\r
+ node_algorithms::unlink_and_rebalance(this_as_node());\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_ISET_HOOK_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_ISLIST_HPP\r
+#define BOOST_INTRUSIVE_ISLIST_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/utility.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <boost/assert.hpp>\r
+#include <boost/type_traits/is_convertible.hpp>\r
+#include <boost/intrusive/islist_hook.hpp>\r
+#include <boost/intrusive/slist_algorithms.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <iterator>\r
+#include <cstddef>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! The class template islist is an intrusive container, that encapsulates \r
+//! a singly-linked list. You can use such a list to squeeze the last bit \r
+//! of performance from your application. Unfortunately, the little gains \r
+//! come with some huge drawbacks. A lot of member functions can't be \r
+//! implemented as efficiently as for standard containers. To overcome \r
+//! this limitation some other member functions with rather unusual semantics \r
+//! have to be introduced.\r
+//!\r
+//! The template parameter ValueTraits is called "value traits". It stores\r
+//! information and operations about the type to be stored in the container.\r
+//!\r
+//! If the user specifies ConstantTimeSize as "true", a member of type SizeType\r
+//! will be embedded in the class, that will keep track of the number of stored objects.\r
+//! This will allow constant-time O(1) size() member, instead of default O(N) size.\r
+//! \r
+//! The iterators of islist are forward iterators. islist provides a static \r
+//! function called "previous" to compute the previous iterator of a given iterator. \r
+//! This function has linear complexity. To improve the usability esp. with \r
+//! the '*_after' functions, ++end() == begin() and previous(begin()) == end() \r
+//! are defined. In addition, whenever you have an end iterator, 'after this \r
+//! iterator' means 'at the beginning of the list'. To improve the self-documentation\r
+//! a "before_begin()" function is defined, returning the end() iterator.\r
+template < class ValueTraits\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t>\r
+class islist\r
+ : private detail::size_holder<ConstantTimeSize, SizeType>\r
+{\r
+ private:\r
+ typedef islist<ValueTraits, ConstantTimeSize, SizeType> this_type; \r
+ typedef typename ValueTraits::node_traits node_traits;\r
+ typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;\r
+\r
+ //! This class is\r
+ //! non-copyable\r
+ islist (const islist&);\r
+\r
+ //! This class is\r
+ //! non-asignable\r
+ islist &operator =(const islist&);\r
+\r
+ //Public typedefs\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits\r
+ <pointer>::difference_type difference_type;\r
+\r
+ class iterator;\r
+ class const_iterator;\r
+ friend class iterator;\r
+ friend class const_iterator;\r
+\r
+ private:\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <pointer, const node>::type const_node_ptr;\r
+ typedef slist_algorithms<node_traits> node_algorithms;\r
+ enum { safemode_or_autounlink = \r
+ (int)ValueTraits::linking_policy == (int)auto_unlink ||\r
+ (int)ValueTraits::linking_policy == (int)safe_mode_link };\r
+\r
+ //Constant-time size is incompatible with auto-unlink hooks!\r
+ BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));\r
+\r
+ node root;\r
+\r
+ node_ptr get_root_node()\r
+ { return node_ptr(&root); }\r
+\r
+ const_node_ptr get_root_node() const\r
+ { return const_node_ptr(&root); }\r
+\r
+ static node_ptr uncast(const_node_ptr ptr)\r
+ {\r
+ using boost::get_pointer;\r
+ return node_ptr(const_cast<node*>(get_pointer(ptr)));\r
+ }\r
+\r
+ static iterator previous_node(iterator beg, iterator i)\r
+ {\r
+ return iterator\r
+ (node_algorithms::get_previous_node(beg.list_node(), i.list_node()));\r
+ }\r
+\r
+ static const_iterator previous_node(const_iterator beg, const_iterator i)\r
+ {\r
+ return const_iterator\r
+ (node_algorithms::get_previous_node(beg.list_node(), i.list_node()));\r
+ }\r
+\r
+ //This functor compares a stored value\r
+ //and the one passed as an argument\r
+ class equal_to_value\r
+ {\r
+ const value_type &t_;\r
+\r
+ public:\r
+ equal_to_value(const value_type &t)\r
+ : t_(t)\r
+ {}\r
+\r
+ bool operator()(const value_type &t)const\r
+ { return t_ == t; }\r
+ };\r
+\r
+ public:\r
+\r
+ //!The forward iterator of the container\r
+ class iterator\r
+ : public detail::slist_iterator<value_type, iterator, node_traits>\r
+ {\r
+ private:\r
+ // gcc warns about an ambiguity between iterator::value_type and\r
+ // islist<ValueTraits>::value_type, thus I introduce a unique name:\r
+ typedef typename islist<ValueTraits, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename islist<ValueTraits, ConstantTimeSize, SizeType>::pointer private_pointer;\r
+ typedef typename islist<ValueTraits, ConstantTimeSize, SizeType>::reference private_reference;\r
+ typedef detail::slist_iterator<private_vt, iterator, node_traits> inherited;\r
+\r
+ public:\r
+ iterator ()\r
+ {}\r
+\r
+ private_pointer operator->() const\r
+ { return ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ private_reference operator*() const\r
+ { return *ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ node_ptr list_node()const\r
+ { return inherited::list_node(); }\r
+\r
+ private:\r
+ explicit iterator (node_ptr node)\r
+ : inherited (node)\r
+ {}\r
+\r
+ friend class islist<ValueTraits, ConstantTimeSize, SizeType>;\r
+ friend class detail::slist_iterator<private_vt, iterator, node_traits>;\r
+ friend class const_iterator;\r
+ };\r
+\r
+ //!The forward const_iterator of the container\r
+ class const_iterator\r
+ : public detail::slist_iterator<const value_type, const_iterator, node_traits>\r
+ {\r
+ private:\r
+ typedef const typename islist<ValueTraits, ConstantTimeSize, SizeType>::value_type private_vt;\r
+ typedef typename islist<ValueTraits, ConstantTimeSize, SizeType>::const_pointer private_pointer;\r
+ typedef typename islist<ValueTraits, ConstantTimeSize, SizeType>::const_reference private_reference;\r
+ typedef detail::slist_iterator<private_vt, const_iterator, node_traits> inherited;\r
+ \r
+ public: \r
+ const_iterator()\r
+ {}\r
+\r
+ const_iterator(const typename islist::iterator& it)\r
+ : inherited (it.list_node())\r
+ {}\r
+\r
+ const_iterator & operator=(const typename islist::iterator& it)\r
+ { return inherited::operator=(it.list_node()); }\r
+\r
+ private_pointer operator->()\r
+ { return ValueTraits::to_value_ptr(this->list_node()); }\r
+\r
+ private_reference operator*()\r
+ { return *ValueTraits::to_value_ptr(this->list_node()); }\r
+ \r
+ private:\r
+ explicit const_iterator (const_node_ptr node)\r
+ : inherited (uncast(node))\r
+ {}\r
+\r
+ friend class islist<ValueTraits, ConstantTimeSize, SizeType>;\r
+ friend class detail::slist_iterator<private_vt, const_iterator, node_traits>;\r
+ };\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: constructs an empty list. \r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks).\r
+ islist()\r
+ {\r
+ size_traits::set_size(size_type(0));\r
+ node_algorithms::init(node_ptr(&root)); \r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Constructs a list equal to [first,last).\r
+ //! \r
+ //! <b>Complexity</b>: Linear in std::distance(b, e). No copy constructors are called. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks).\r
+ template<class Iterator>\r
+ islist(Iterator b, Iterator e)\r
+ {\r
+ size_traits::set_size(size_type(0));\r
+ node_algorithms::init(node_ptr(&root));\r
+ insert_after(before_begin(), b, e);\r
+ }\r
+\r
+ //! <b>Effects</b>: If it's a safe-mode\r
+ //! or auto-unlink value, the destructor does nothing\r
+ //! (ie. no code is generated). Otherwise it detaches all elements from this. \r
+ //! In this case the objects in the list are not deleted (i.e. no destructors \r
+ //! are called), but the hooks according to the ValueTraits template parameter\r
+ //! are set to their default value.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the list, if \r
+ //! it's a safe-mode or auto-unlink value. Otherwise constant.\r
+ ~islist()\r
+ { this->clear(); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements of the list.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the erased elements.\r
+ void clear()\r
+ {\r
+ if(safemode_or_autounlink){\r
+ this->erase_after(this->before_begin(), this->end()); \r
+ }\r
+ else{\r
+ node_algorithms::init(node_ptr(&root));\r
+ size_traits::set_size(size_type(0));\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements of the container\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements of the list.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased elements.\r
+ template <class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ { this->erase_after_and_destroy(this->before_begin(), this->end(), destroyer); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue.\r
+ //! \r
+ //! <b>Effects</b>: Inserts the value in the front of the list.\r
+ //! No copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ void push_front(value_type &value) \r
+ {\r
+ node_ptr to_insert(ValueTraits::to_node_ptr(value));\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(to_insert));\r
+ node_algorithms::link_after(get_root_node(), to_insert); \r
+ size_traits::increment();\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the first element of the list.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the erased element.\r
+ void pop_front() \r
+ {\r
+ node_ptr to_erase = node_traits::get_next(get_root_node());\r
+ node_algorithms::unlink_after(get_root_node());\r
+ size_traits::decrement();\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the first element of the list.\r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased element.\r
+ template<class Destroyer>\r
+ void pop_front_and_destroy(Destroyer destroyer)\r
+ {\r
+ node_ptr to_erase = node_traits::get_next(get_root_node());\r
+ this->pop_front();\r
+ destroyer(ValueTraits::to_value_ptr(to_erase));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a reference to the first element of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ reference front()\r
+ { return *ValueTraits::to_value_ptr(node_traits::get_next(get_root_node())); }\r
+\r
+ //! <b>Effects</b>: Returns a const_reference to the first element of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_reference front() const\r
+ { return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(const_node_ptr(&root)))); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ iterator begin() \r
+ { return iterator (node_traits::get_next(get_root_node())); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_iterator begin() const \r
+ { return const_iterator (node_traits::get_next(get_root_node())); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator to the end of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ iterator end() \r
+ { return iterator (get_root_node()); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator to the end of the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_iterator end() const \r
+ { return const_iterator (get_root_node()); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator that points to a position\r
+ //! before the first element. Equivalent to "end()"\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ iterator before_begin() \r
+ { return end(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator that points to a position\r
+ //! before the first element. Equivalent to "end()"\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ const_iterator before_begin() const \r
+ { return end(); }\r
+\r
+ //! <b>Effects</b>: Returns the number of the elements contained in the list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements contained in the list.\r
+ //! if ConstantTimeSize is false. Constant time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ size_type size() const\r
+ {\r
+ if(ConstantTimeSize)\r
+ return size_traits::get_size();\r
+ else\r
+ return node_algorithms::count(const_node_ptr(&root)) - 1; \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns true if the list contains no elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ bool empty() const\r
+ { return node_algorithms::unique(get_root_node()); }\r
+\r
+ //! <b>Effects</b>: Swaps the elements of x and *this.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements of both lists.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ void swap(islist& other)\r
+ {\r
+ node_algorithms::swap_nodes(get_root_node(), &other.root);\r
+ if(ConstantTimeSize){\r
+ size_type backup = size_traits::get_size();\r
+ size_traits::set_size(other.get_size());\r
+ other.set_size(backup);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws.\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const islist &src, Cloner cloner, Destroyer destroyer)\r
+ { \r
+ clone_and_reverse_from(src, cloner, destroyer);\r
+ this->reverse();\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this in the reverse order than\r
+ //! the original container.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws.\r
+ //! \r
+ //! <b>Note</b>: This function is more efficient than "clone_from".\r
+ template <class Cloner, class Destroyer>\r
+ void clone_and_reverse_from(const islist &src, Cloner cloner, Destroyer destroyer)\r
+ {\r
+ this->clear_and_destroy(destroyer);\r
+ try{\r
+ const_iterator b(src.begin()), e(src.end());\r
+ for(; b != e; ++b){\r
+ this->push_front(*cloner(*b));\r
+ }\r
+ }\r
+ catch(...){\r
+ clear_and_destroy(destroyer);\r
+ throw;\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and prev_p must point to an element\r
+ //! contained by the list or to end().\r
+ //!\r
+ //! <b>Effects</b>: Inserts the value after the position pointed by prev_p.\r
+ //! No copy constructor is called.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the inserted element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ iterator insert_after(iterator prev_p, value_type &value)\r
+ {\r
+ node_ptr n = ValueTraits::to_node_ptr(value);\r
+ if(safemode_or_autounlink)\r
+ BOOST_ASSERT(node_algorithms::unique(n));\r
+ node_algorithms::link_after(prev_p.list_node(), n);\r
+ size_traits::increment();\r
+ return iterator (n);\r
+ }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type and prev_p must point to an element\r
+ //! contained by the list or to the end node.\r
+ //! \r
+ //! <b>Effects</b>: Inserts the [first, last)\r
+ //! after the position prev_p.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ template<class Iterator>\r
+ void insert_after(iterator prev_p, Iterator first, Iterator last)\r
+ {\r
+ for (; first != last; ++first)\r
+ prev_p = insert_after(prev_p, *first);\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and p must point to an element\r
+ //! contained by the list or to end().\r
+ //!\r
+ //! <b>Effects</b>: Inserts the value before the position pointed by p.\r
+ //! No copy constructor is called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements before p. \r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ iterator insert(iterator p, value_type &value)\r
+ { return insert_after(this->previous(p), value); }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type and p must point to an element \r
+ //! contained by the list or to the end node.\r
+ //! \r
+ //! <b>Effects</b>: Inserts the pointed by b and e\r
+ //! before the position p. No copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted plus linear\r
+ //! to the elements before b.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ template<class Iterator>\r
+ void insert(iterator p, Iterator b, Iterator e)\r
+ { return insert_after(this->previous(p), b, e); }\r
+\r
+ //! <b>Effects</b>: Erases the element after the element pointed by prev of \r
+ //! the list. No destructors are called.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased element.\r
+ iterator erase_after(iterator prev)\r
+ {\r
+ iterator it(prev); ++it;\r
+ node_ptr to_erase(it.list_node());\r
+ node_algorithms::unlink_after(prev.list_node());\r
+ size_traits::decrement();\r
+ iterator ret(++prev);\r
+ if(safemode_or_autounlink)\r
+ node_algorithms::init(to_erase);\r
+ return ret;\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the range (before_first, last) from\r
+ //! the list. No destructors are called.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Lineal to the elements (last - before_first).\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased element.\r
+ iterator erase_after(iterator before_first, iterator last)\r
+ {\r
+ iterator first;\r
+ while(++(first = before_first) != last){\r
+ this->erase_after(before_first);\r
+ }\r
+ return last;\r
+ }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed by i of the list. \r
+ //! No destructors are called.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed element,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the elements before i.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased element.\r
+ iterator erase(iterator i)\r
+ { return this->erase_after(this->previous(i)); }\r
+\r
+ //! <b>Requires</b>: first and last must be valid iterator to elements in *this.\r
+ //! \r
+ //! <b>Effects</b>: Erases the range pointed by b and e.\r
+ //! No destructors are called.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements erased plus linear\r
+ //! to the elements before first.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased elements.\r
+ iterator erase(iterator first, iterator last)\r
+ { return erase_after(this->previous(first), last); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element after the element pointed by prev of \r
+ //! the list.\r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased element.\r
+ template<class Destroyer>\r
+ iterator erase_after_and_destroy(iterator prev, Destroyer destroyer)\r
+ {\r
+ iterator it(prev); ++it;\r
+ node_ptr to_erase(it.list_node());\r
+ iterator ret(this->erase_after(prev));\r
+ destroyer(ValueTraits::to_value_ptr(to_erase));\r
+ return ret;\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the range (before_first, last) from\r
+ //! the list.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Lineal to the elements (last - before_first).\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators to the erased element.\r
+ template<class Destroyer>\r
+ iterator erase_after_and_destroy(iterator before_first, iterator last, Destroyer destroyer)\r
+ {\r
+ iterator first;\r
+ while(++(first = before_first) != last){\r
+ this->erase_after_and_destroy(before_first, destroyer);\r
+ }\r
+ return last;\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed by i of the list. \r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed element,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the elements before i.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased element.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator i, Destroyer destroyer)\r
+ { return this->erase_after_and_destroy(this->previous(i), destroyer); }\r
+\r
+ //! <b>Requires</b>: first and last must be valid iterator to elements in *this.\r
+ //! Destroyer::operator()(pointer) shouldn't throw.\r
+ //! \r
+ //! <b>Effects</b>: Erases the range pointed by b and e.\r
+ //! No destructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,\r
+ //! or end() if no such element exists.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements erased plus linear\r
+ //! to the elements before first.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references) to the\r
+ //! erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(iterator first, iterator last, Destroyer destroyer)\r
+ { return erase_after_and_destroy(this->previous(first), last, destroyer); }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Clears the list and inserts the range pointed by b and e.\r
+ //! No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted plus\r
+ //! linear to the elements contained in the list if it's a safe-mode\r
+ //! or auto-unlink value.\r
+ //! Linear to the number of elements inserted in the list otherwise.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements.\r
+ template<class Iterator>\r
+ void assign(Iterator b, Iterator e)\r
+ {\r
+ this->clear();\r
+ this->insert_after(before_begin(), b, e);\r
+ }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Requires</b>: Dereferencing iterator must yield \r
+ //! an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Clears the list and inserts the range pointed by b and e.\r
+ //! No destructors or copy constructors are called.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements inserted plus\r
+ //! linear to the elements contained in the list.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements.\r
+ template<class Iterator, class Destroyer>\r
+ void assign_and_destroy(Iterator b, Iterator e, Destroyer destroyer)\r
+ {\r
+ this->clear_and_destroy(destroyer);\r
+ this->insert_after_and_destroy(before_begin(), b, e, destroyer);\r
+ }\r
+\r
+ //! <b>Requires</b>: prev is an iterator to an element or x.end()/x.before_begin() in x.\r
+ //! \r
+ //! <b>Effects</b>: Transfers all the elements of list x to this list, after the\r
+ //! the element pointed by prev. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Returns</b>: The last element inserted of x or prev if x is empty.\r
+ //! This iterator can be used as new "prev" iterator for a new splice_after call.\r
+ //! that will splice new values after the previously spliced values.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //!\r
+ //! <b>Complexity</b>: Linear to the elements contained in x\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ iterator splice_after(iterator prev, islist &x)\r
+ {\r
+ if (!x.empty()){\r
+ iterator last_x(x.previous(x.end()));\r
+ node_algorithms::transfer_after\r
+ ( prev.list_node()\r
+ , x.end().list_node()\r
+ , last_x.list_node());\r
+ size_traits::set_size(size_traits::get_size() + x.get_size());\r
+ x.set_size(size_type(0));\r
+ return last_x;\r
+ }\r
+ else{\r
+ return prev;\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: prev must point to an element contained by this list or\r
+ //! to the before_begin() element. prev_ele must point to an element contained in list\r
+ //! x or must be x.before_begin().\r
+ //! \r
+ //! <b>Effects</b>: Transfers the element after prev_ele, from list x to this list, \r
+ //! after the element pointed by prev. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice_after(iterator prev, islist &x, iterator prev_ele)\r
+ {\r
+ iterator nxt = prev_ele;\r
+ ++nxt;\r
+ if (nxt != prev && prev_ele != prev){\r
+ node_algorithms::transfer_after\r
+ (prev.list_node(), prev_ele.list_node(), nxt.list_node());\r
+ size_traits::increment();\r
+ x.decrement();\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: prev_pos must be a dereferenceable iterator in *this or be\r
+ //! before_begin(), and before_first and before_last belong to x and\r
+ //! ++before_first != x.end() && before_last != x.end(). \r
+ //! \r
+ //! <b>Effects</b>: Transfers the range (before_first, before_last] from list x to this\r
+ //! list, after the element pointed by prev_pos.\r
+ //! No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements transferred\r
+ //! if ConstantTimeSize is true. Constant-time otherwise.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice_after(iterator prev_pos, islist &x, iterator before_first, iterator before_last)\r
+ {\r
+ if (before_first != before_last){\r
+ if(ConstantTimeSize){\r
+ size_type increment = std::distance(before_first, before_last);\r
+ node_algorithms::transfer_after\r
+ (prev_pos.list_node(), before_first.list_node(), before_last.list_node());\r
+ size_traits::set_size(size_traits::get_size() + increment);\r
+ x.set_size(x.get_size() - increment);\r
+ }\r
+ else{\r
+ node_algorithms::transfer_after\r
+ (prev_pos.list_node(), before_first.list_node(), before_last.list_node());\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: prev_pos must be a dereferenceable iterator in *this or be\r
+ //! before_begin(), and before_first and before_last belong to x and\r
+ //! ++before_first != x.end() && before_last != x.end() and\r
+ //! n == std::distance(before_first, before_last).\r
+ //! \r
+ //! <b>Effects</b>: Transfers the range (before_first, before_last] from list x to this\r
+ //! list, after the element pointed by p. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice_after(iterator prev_pos, islist &x, iterator before_first, iterator before_last, difference_type n)\r
+ {\r
+ if(n){\r
+ if(ConstantTimeSize){\r
+ BOOST_ASSERT(std::distance(before_first, before_last) == n);\r
+ node_algorithms::transfer_after\r
+ (prev_pos.list_node(), before_first.list_node(), before_last.list_node());\r
+ size_traits::set_size(size_traits::get_size() + n);\r
+ x.set_size(x.get_size() - n);\r
+ }\r
+ else{\r
+ node_algorithms::transfer_after\r
+ (prev_pos.list_node(), before_first.list_node(), before_last.list_node());\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: it is an iterator to an element in x.\r
+ //! \r
+ //! <b>Effects</b>: Transfers all the elements of list x to this list, before the\r
+ //! the element pointed by it. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Returns</b>: The last element inserted of x or the previous element\r
+ //! of it if x is empty.\r
+ //! This iterator can be used as new "prev" iterator for a new splice call.\r
+ //! that will splice new values after the previously spliced values.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //!\r
+ //! <b>Complexity</b>: Linear to the elements contained in x plus linear to\r
+ //! the elements before it.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ iterator splice(iterator it, islist &x)\r
+ { return splice_after(this->previous(it), x); }\r
+\r
+ //! <b>Requires</b>: it p must be a valid iterator of *this.\r
+ //! elem must point to an element contained in list\r
+ //! x.\r
+ //! \r
+ //! <b>Effects</b>: Transfers the element elem, from list x to this list, \r
+ //! before the element pointed by pos. No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the elements before pos and before elem.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator pos, islist &x, iterator elem)\r
+ { return splice_after(this->previous(pos), x, this->previous(elem)); }\r
+\r
+ //! <b>Requires</b>: pos must be a dereferenceable iterator in *this\r
+ //! and first and last belong to x and first and last a valid range on x. \r
+ //! \r
+ //! <b>Effects</b>: Transfers the range [first, last) from list x to this\r
+ //! list, before the element pointed by pos.\r
+ //! No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the sum of elements before pos, first, and last.\r
+ //! Plus linear to the number of elements transferred if ConstantTimeSize is true.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator pos, islist &x, iterator first, iterator last)\r
+ { return splice_after(this->previous(pos), x, this->previous(first), this->previous(last)); }\r
+\r
+ //! <b>Requires</b>: pos must be a dereferenceable iterator in *this\r
+ //! and first and last belong to x and first and last a valid range on x. \r
+ //! n == std::distance(first, last).\r
+ //! \r
+ //! <b>Effects</b>: Transfers the range [first, last) from list x to this\r
+ //! list, before the element pointed by pos.\r
+ //! No destructors or copy constructors are called.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the sum of elements before pos, first, and last.\r
+ //! \r
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this\r
+ //! list. Iterators of this list and all the references are not invalidated.\r
+ void splice(iterator pos, islist &x, iterator first, iterator last, difference_type n)\r
+ { return splice_after(this->previous(pos), x, this->previous(first), this->previous(last), n); }\r
+\r
+ //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>. \r
+ //! The sort is stable, that is, the relative order of equivalent elements is preserved.\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the predicate throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N\r
+ //! is the list's size.\r
+ //!\r
+ //! <b>Note</b>: Iterators and references are not invalidated\r
+ template<class Predicate>\r
+ void sort(Predicate p)\r
+ {\r
+ if (!this->empty() &&\r
+ node_traits::get_next(node_traits::get_next(get_root_node()))\r
+ != this->get_root_node()) {\r
+ islist carry;\r
+ islist counter[64];\r
+ int fill = 0;\r
+ iterator last_inserted;\r
+ while(!this->empty()){\r
+ last_inserted = this->begin();\r
+ carry.splice_after(carry.before_begin(), *this, this->before_begin());\r
+ int i = 0;\r
+ while(i < fill && !counter[i].empty()) {\r
+ last_inserted = carry.merge(counter[i++], p);\r
+ }\r
+ BOOST_ASSERT(counter[i].empty());\r
+\r
+ iterator last_element(previous_node(last_inserted, carry.end()));\r
+ if(ConstantTimeSize){\r
+ counter[i].splice_after( counter[i].end(), carry\r
+ , carry.before_begin(), last_element\r
+ , carry.size());\r
+ }\r
+ else{\r
+ counter[i].splice_after( counter[i].end(), carry\r
+ , carry.before_begin(), last_element);\r
+ }\r
+ //counter[i].splice_after(counter[i].end(), carry, carry.end(), previous_node(last_inserted, carry.end()));\r
+ //carry.swap(counter[i]);\r
+ if(i == fill)\r
+ ++fill;\r
+ }\r
+\r
+ for (int i = 1; i < fill; ++i)\r
+ last_inserted = counter[i].merge(counter[i-1], p);\r
+ //this->swap(counter[fill-1]);\r
+ BOOST_ASSERT(this->empty());\r
+\r
+ iterator last_element(previous_node(last_inserted, counter[--fill].end()));\r
+ if(ConstantTimeSize){\r
+ this->splice_after( end(), counter[fill], counter[fill].before_begin()\r
+ , last_element, counter[fill].size());\r
+ }\r
+ else{\r
+ this->splice_after( end(), counter[fill], counter[fill].before_begin()\r
+ , last_element);\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: p must be a comparison function that induces a strict weak\r
+ //! ordering and both *this and x must be sorted according to that ordering\r
+ //! The lists x and *this must be distinct. \r
+ //! \r
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them\r
+ //! in order into *this. The merge is stable; that is, if an element from *this is \r
+ //! equivalent to one from x, then the element from *this will precede the one from x. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or std::less<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time: it performs at most\r
+ //! size() + x.size() - 1 comparisons.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ void sort()\r
+ { this->sort(std::less<value_type>()); }\r
+\r
+ //! <b>Requires</b>: p must be a comparison function that induces a strict weak\r
+ //! ordering and both *this and x must be sorted according to that ordering\r
+ //! The lists x and *this must be distinct. \r
+ //! \r
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them\r
+ //! in order into *this. The merge is stable; that is, if an element from *this is \r
+ //! equivalent to one from x, then the element from *this will precede the one from x. \r
+ //! \r
+ //! <b>Returns</b>: An iterator to the last transferred value, end() is x is empty.\r
+ //! \r
+ //! <b>Throws</b>: If the predicate throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time: it performs at most\r
+ //! size() + x.size() - 1 comparisons.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ template<class Predicate>\r
+ iterator merge(islist& x, Predicate p) \r
+ {\r
+ iterator a(before_begin()), e(end()), ax(x.before_begin());\r
+ iterator last_inserted(e);\r
+ iterator a_next;\r
+ while(++(a_next = a) != e && !x.empty()) {\r
+ iterator ix(ax);\r
+ iterator cx;\r
+ size_type n(0);\r
+ while(++(cx = ix) != ax && p(*cx, *a_next)){\r
+ ++ix; ++n;\r
+ }\r
+ if(ax != ix){\r
+ this->splice_after(a, x, ax, ix, n);\r
+ last_inserted = ix;\r
+ }\r
+ a = a_next;\r
+ } \r
+ if (!x.empty()){\r
+ last_inserted = this->splice_after(a, x);\r
+ }\r
+ return last_inserted;\r
+ }\r
+\r
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them\r
+ //! in order into *this according to std::less<value_type>. The merge is stable; \r
+ //! that is, if an element from *this is equivalent to one from x, then the element \r
+ //! from *this will precede the one from x. \r
+ //! \r
+ //! <b>Throws</b>: if std::less<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time: it performs at most\r
+ //! size() + x.size() - 1 comparisons.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated\r
+ void merge(islist& x)\r
+ { this->merge(x, std::less<value_type>()); }\r
+\r
+ //! <b>Effects</b>: Reverses the order of elements in the list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear to the contained elements.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated\r
+ void reverse() \r
+ { node_algorithms::reverse(node_ptr(&root)); }\r
+\r
+ //! <b>Effects</b>: Removes all the elements that compare equal to value.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If std::equal_to<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid. This function is \r
+ //! linear time: it performs exactly size() comparisons for equality.\r
+ void remove(const value_type &value)\r
+ { remove_if(equal_to_value(value)); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes all the elements that compare equal to value.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //!\r
+ //! <b>Throws</b>: If std::equal_to<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Destroyer>\r
+ void remove_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { remove_and_destroy_if(equal_to_value(value), destroyer); }\r
+\r
+ //! <b>Effects</b>: Removes all the elements for which a specified\r
+ //! predicate is satisfied. No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If pred throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() calls to the predicate.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Pred>\r
+ void remove_if(Pred pred)\r
+ { remove_and_destroy_if(pred, detail::null_destroyer()); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes all the elements for which a specified\r
+ //! predicate is satisfied.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //!\r
+ //! <b>Throws</b>: If pred throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.\r
+ //!\r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Pred, class Destroyer>\r
+ void remove_and_destroy_if(Pred pred, Destroyer destroyer)\r
+ {\r
+ iterator bcur(this->before_begin()), cur, e(this->end());\r
+ \r
+ while(++(cur = bcur) != e){\r
+ if (pred(*cur)){\r
+ pointer p = cur.operator->();\r
+ this->erase_after(bcur);\r
+ destroyer(p);\r
+ }\r
+ else{\r
+ ++bcur;\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that are equal from the list. No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If std::equal_to<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1) comparisons calls to pred()).\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ void unique()\r
+ { unique_and_destroy(std::equal_to<value_type>(), detail::null_destroyer()); }\r
+\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that satisfy some binary predicate from the list.\r
+ //! No destructors are called.\r
+ //! \r
+ //! <b>Throws</b>: If the predicate throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1) comparisons equality comparisons.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class BinaryPredicate>\r
+ void unique(BinaryPredicate pred)\r
+ { unique_and_destroy(pred, detail::null_destroyer()); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that satisfy some binary predicate from the list.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //! \r
+ //! <b>Throws</b>: If std::equal_to<value_type> throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1) comparisons equality comparisons.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class Destroyer>\r
+ void unique_and_destroy(Destroyer destroyer)\r
+ { unique(std::equal_to<value_type>(), destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent \r
+ //! elements that satisfy some binary predicate from the list.\r
+ //! Destroyer::operator()(pointer) is called for every removed element.\r
+ //! \r
+ //! <b>Throws</b>: If the predicate throws. Basic guarantee.\r
+ //! \r
+ //! <b>Complexity</b>: Linear time (size()-1) comparisons equality comparisons.\r
+ //! \r
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,\r
+ //! and iterators to elements that are not removed remain valid.\r
+ template<class BinaryPredicate, class Destroyer>\r
+ void unique_and_destroy(BinaryPredicate pred, Destroyer destroyer)\r
+ {\r
+ iterator end_n(end());\r
+ iterator cur(begin());\r
+ iterator cur_next;\r
+\r
+ if (cur != end_n) {\r
+ while(++(cur_next = cur) != end_n) {\r
+ if (pred(*cur, *cur_next)){\r
+ pointer p = cur_next.operator->();\r
+ this->erase_after(cur);\r
+ destroyer(p);\r
+ }\r
+ else{\r
+ ++cur;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: value must be a reference to a value inserted in a list.\r
+ //! \r
+ //! <b>Effects</b>: This function returns a const_iterator pointing to the element\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ static iterator current(value_type &value) \r
+ { \r
+ BOOST_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(value)));\r
+ return iterator (ValueTraits::to_node_ptr(value)); \r
+ }\r
+\r
+ //! <b>Requires</b>: value must be a const reference to a value inserted in a list.\r
+ //! \r
+ //! <b>Effects</b>: This function returns an iterator pointing to the element.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Note</b>: Iterators and references are not invalidated.\r
+ static const_iterator current(const value_type &value) \r
+ { \r
+ BOOST_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast<value_type&> (value))));\r
+ return const_iterator (ValueTraits::to_node_ptr(const_cast<value_type&> (value))); \r
+ }\r
+\r
+ //! <b>Returns</b>: The iterator to the element before i in the list. \r
+ //! Returns the end-iterator, if either i is the begin-iterator or the \r
+ //! list is empty. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements before i. \r
+ iterator previous(iterator i)\r
+ {\r
+ return iterator\r
+ (node_algorithms::get_previous_node\r
+ (before_begin().list_node(), i.list_node()));\r
+ }\r
+\r
+ //! <b>Returns</b>: The const_iterator to the element before i in the list. \r
+ //! Returns the end-const_iterator, if either i is the begin-const_iterator or \r
+ //! the list is empty. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements before i. \r
+ const_iterator previous(const_iterator i) const\r
+ {\r
+ return const_iterator\r
+ (node_algorithms::get_previous_node\r
+ (before_begin().list_node(), i.list_node()));\r
+ }\r
+};\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator==(const islist<V, C, S>& x, const islist<V, C, S>& y)\r
+{\r
+ if(C && x.size() != y.size()){\r
+ return false;\r
+ }\r
+ typedef typename islist<V, C, S>::const_iterator const_iterator;\r
+ const_iterator end1 = x.end();\r
+\r
+ const_iterator i1 = x.begin();\r
+ const_iterator i2 = y.begin();\r
+ if(C){\r
+ while (i1 != end1 && *i1 == *i2) {\r
+ ++i1;\r
+ ++i2;\r
+ }\r
+ return i1 == end1;\r
+ }\r
+ else{\r
+ const_iterator end2 = y.end();\r
+ while (i1 != end1 && i2 != end2 && *i1 == *i2) {\r
+ ++i1;\r
+ ++i2;\r
+ }\r
+ return i1 == end1 && i2 == end2;\r
+ }\r
+}\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator<(const islist<V, C, S>& x,\r
+ const islist<V, C, S>& y)\r
+{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator!=(const islist<V, C, S>& x, const islist<V, C, S>& y) \r
+{ return !(x == y); }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator>(const islist<V, C, S>& x, const islist<V, C, S>& y) \r
+{ return y < x; }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator<=(const islist<V, C, S>& x, const islist<V, C, S>& y) \r
+{ return !(y < x); }\r
+\r
+template <class V, bool C, class S>\r
+inline bool operator>=(const islist<V, C, S>& x, const islist<V, C, S>& y) \r
+{ return !(x < y); }\r
+\r
+template <class V, bool C, class S>\r
+inline void swap(islist<V, C, S>& x, islist<V, C, S>& y)\r
+{ x.swap(y); }\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_ISLIST_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_ISLIST_HOOK_HPP\r
+#define BOOST_INTRUSIVE_ISLIST_HOOK_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/utilities.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/detail/slist_node.hpp>\r
+#include <boost/intrusive/slist_algorithms.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <stdexcept>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! Derive a class from islist_base_hook in order to store objects in \r
+//! in an islist. islist_base_hook holds the data necessary to maintain the \r
+//! list and provides an appropriate value_traits class for islist.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one islist_base_hook, then each islist_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the islist configured from this hook.\r
+template<typename Tag, bool SafeMode = true, class VoidPointer = void*>\r
+class islist_base_hook\r
+ : private detail::slist_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::slist_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+\r
+ private:\r
+ typedef slist_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef islist_base_hook\r
+ <Tag, SafeMode, VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ islist_base_hook()\r
+ : node_traits::node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using islist_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ islist_base_hook(const islist_base_hook& )\r
+ : node_traits::node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using islist_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ islist_base_hook& operator=(const islist_base_hook& )\r
+ { \r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ return *this; \r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an islist an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~islist_base_hook() \r
+ { \r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Linear\r
+ //!\r
+ //! <b>Throws</b>: Nothing. \r
+ void swap_nodes(islist_base_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Precondition</b>: The hook must be in safe-mode.\r
+ //!\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether islist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant\r
+ bool linked() const \r
+ {\r
+ //linked() can be only used in safe-mode\r
+ BOOST_ASSERT(SafeMode);\r
+ return !node_algorithms::unique(this_as_node());\r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for islist. \r
+ //! The template argument T defines the class type stored in islist. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<islist_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<const islist_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+\r
+//! Derive a class from islist_auto_base_hook in order to store objects in \r
+//! in an islist. islist_auto_base_hook holds the data necessary to maintain the \r
+//! list and provides an appropriate value_traits class for islist.\r
+//!\r
+//! The difference between islist_auto_base_hook and islist_base_hook is that\r
+//! islist_auto_base_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! islist_auto_base_hook can only be used with non constant-time islists.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one islist_auto_base_hook, then each islist_auto_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the islist configured from this hook.\r
+template<typename Tag, class VoidPointer = void*>\r
+class islist_auto_base_hook\r
+ : private detail::slist_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::slist_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = auto_unlink };\r
+\r
+ private:\r
+ typedef slist_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef islist_auto_base_hook\r
+ <Tag, VoidPointer> this_type;\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ islist_auto_base_hook()\r
+ : node_traits::node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using islist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ islist_auto_base_hook(const islist_auto_base_hook& )\r
+ : node_traits::node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using islist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ islist_auto_base_hook& operator=(const islist_auto_base_hook& )\r
+ { this->unlink(); return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~islist_auto_base_hook() \r
+ { this->unlink(); }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Linear \r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ void swap_nodes(islist_auto_base_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether islist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return !node_algorithms::unique(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ {\r
+ node_algorithms::unlink(this_as_node());\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for islist. \r
+ //! The template argument T defines the class type stored in islist. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<islist_auto_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<const islist_auto_base_hook*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+\r
+//! Put a public data member islist_member_hook in order to store objects of this class in\r
+//! an islist. islist_member_hook holds the data necessary for maintaining the list and \r
+//! provides an appropriate value_traits class for islist.\r
+//! \r
+//! The template argument T defines the class type stored in islist. Objects of type \r
+//! T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//! \r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the islist configured from this hook.\r
+template<class T, bool SafeMode = true, class VoidPointer = void*>\r
+class islist_member_hook \r
+ : private detail::slist_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::slist_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+\r
+ private:\r
+ typedef slist_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef islist_member_hook<T, SafeMode, VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type >::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type >::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ islist_member_hook()\r
+ : node_traits::node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using islist_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ islist_member_hook(const islist_member_hook& )\r
+ : node_traits::node()\r
+ {\r
+ if(SafeMode){\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using islist_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ islist_member_hook& operator=(const islist_member_hook& ) \r
+ { \r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ return *this; \r
+ }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an islist an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~islist_member_hook() \r
+ { \r
+ if(SafeMode){\r
+ BOOST_ASSERT(!this->linked());\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Linear \r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ void swap_nodes(islist_member_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Precondition</b>: The hook must be in safe-mode.\r
+ //!\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether islist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant\r
+ bool linked() const \r
+ {\r
+ //We must be in safe-mode to know if we are really linked\r
+ //Otherwise, this would lead to an unknown state\r
+ BOOST_ASSERT(SafeMode);\r
+ return !node_algorithms::unique(this_as_node()); \r
+ }\r
+\r
+ //! The value_traits class is used as the first template argument for islist. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+\r
+//! Put a public data member islist_auto_member_hook in order to store objects of this class in\r
+//! an islist. islist_auto_member_hook holds the data necessary for maintaining the list and \r
+//! provides an appropriate value_traits class for islist.\r
+//!\r
+//! The difference between islist_auto_member_hook and islist_member_hook is that\r
+//! islist_auto_member_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! islist_auto_member_hook can only be used with non constant-time islists.\r
+//! \r
+//! The first template argument T defines the class type stored in islist. Objects of\r
+//! type T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the islist configured from this hook.\r
+template<class T, class VoidPointer = void*>\r
+class islist_auto_member_hook \r
+ : private detail::slist_node_traits<VoidPointer>::node\r
+{\r
+ public:\r
+ typedef detail::slist_node_traits<VoidPointer> node_traits;\r
+ enum { linking_policy = auto_unlink };\r
+\r
+ private:\r
+ typedef slist_algorithms<node_traits> node_algorithms;\r
+\r
+ public:\r
+ typedef typename node_traits::node node;\r
+ typedef islist_auto_member_hook<T, VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type >::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type >::type const_this_type_ptr;\r
+\r
+ private:\r
+ node_ptr this_as_node()\r
+ { return node_ptr(static_cast<node *const>(this)); }\r
+\r
+ const_node_ptr this_as_node() const\r
+ { return const_node_ptr(static_cast<const node *const>(this)); }\r
+\r
+ public:\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ islist_auto_member_hook()\r
+ : node_traits::node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using islist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ islist_auto_member_hook(const islist_auto_member_hook& )\r
+ : node_traits::node()\r
+ { node_algorithms::init(this_as_node()); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using islist_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ islist_auto_member_hook& operator=(const islist_auto_member_hook& ) \r
+ { this->unlink(); return *this; }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an islist an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~islist_auto_member_hook() \r
+ { this->unlink(); }\r
+\r
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements \r
+ //! related to those nodes in one or two containers. That is, if the node \r
+ //! this is part of the element e1, the node x is part of the element e2 \r
+ //! and both elements are included in the containers s1 and s2, then after \r
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 \r
+ //! at the position of e1. If one element is not in a container, then \r
+ //! after the swap-operation the other element is not in a container. \r
+ //! Iterators to e1 and e2 related to those nodes are invalidated. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ void swap_nodes(islist_auto_member_hook& other) \r
+ { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether islist::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return !node_algorithms::unique(this_as_node()); }\r
+\r
+ //! The value_traits class is used as the first template argument for islist. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ {\r
+ node_algorithms::unlink(this_as_node());\r
+ node_algorithms::init(this_as_node());\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr(static_cast<this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr(static_cast<const this_type*> (get_pointer(p))); \r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return this_as_node(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return this_as_node(); }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include<boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_ISLIST_HOOK_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#ifndef BOOST_INTRUSIVE_IHASHSET_HPP\r
+#define BOOST_INTRUSIVE_IHASHSET_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/ihashtable.hpp>\r
+#include <iterator>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! The class template iunordered_set is an intrusive container, that mimics most of \r
+//! the interface of std::tr1::unordered_set as described in the C++ TR1.\r
+//!\r
+//! iunordered_set is a pseudo-intrusive container: each object to be stored in the\r
+//! container must contain a proper hook, but the container also needs\r
+//! additional auxiliary memory to work: iunordered_set needs a pointer to an array\r
+//! of type `bucket_type` to be passed in the constructor. This bucket array must\r
+//! have at least the same lifetime as the container. This makes the use of\r
+//! iunordered_set more complicated than purely intrusive containers.\r
+//! `bucket_type` is default-constructible, copyable and assignable\r
+//!\r
+//! The template parameter ValueTraits is called "value traits". It stores\r
+//! information and operations about the type to be stored in the container.\r
+//!\r
+//! The template parameter Hash is a unary function object that take an argument\r
+//! of type ValueTraits::value_type and returns a value of type std::size_t.\r
+//!\r
+//! The template parameter Equal is a binary predicate that takes two arguments of\r
+//! type ValueTraits::value_type. Equal is an equivalence relation.\r
+//!\r
+//! If the user specifies ConstantTimeSize as "true", a member of type SizeType\r
+//! will be embedded in the class, that will keep track of the number of stored objects.\r
+//! This will allow constant-time O(1) size() member, instead of default O(N) size.\r
+//!\r
+//! iunordered_set only provides forward iterators but it provides 4 iterator types:\r
+//! iterator and const_iterator to navigate through the whole container and\r
+//! local_iterator and const_local_iterator to navigate through the values\r
+//! stored in a single bucket. Local iterators are faster and smaller.\r
+//!\r
+//! It's not recommended to use non ConstantTimeSize iunordered_sets because several\r
+//! key functions, like "empty()", become non-constant time functions. Non\r
+//! ConstantTimeSize iunordered_sets are mainly provided to support auto-unlink hooks.\r
+//!\r
+//! iunordered_set, unlike std::unordered_set, does not make automatic rehashings nor\r
+//! offers functions related to a load factor. Rehashing can be explicitly requested\r
+//! and the user must provide a new bucket array that will be used from that moment.\r
+//!\r
+//! Since no automatic rehashing is done, iterators are never invalidated when\r
+//! inserting or erasing elements. Iterators are only invalidated when rehasing.\r
+template< class ValueTraits\r
+ , class Hash = boost::hash<typename ValueTraits::value_type>\r
+ , class Equal = std::equal_to<typename ValueTraits::value_type>\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t\r
+ >\r
+class iunordered_set\r
+{\r
+ private:\r
+ typedef detail::ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType> table_type;\r
+\r
+ //! This class is\r
+ //! non-copyable\r
+ iunordered_set (const iunordered_set&);\r
+\r
+ //! This class is\r
+ //! non-assignable\r
+ iunordered_set &operator =(const iunordered_set&);\r
+\r
+ typedef table_type implementation_defined;\r
+\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;\r
+ typedef value_type key_type;\r
+ typedef Equal key_equal;\r
+ typedef Hash hasher;\r
+ typedef typename implementation_defined::bucket_type bucket_type;\r
+ typedef typename boost::pointer_to_other<pointer, bucket_type>::type bucket_ptr;\r
+ typedef typename implementation_defined::iterator iterator;\r
+ typedef typename implementation_defined::const_iterator const_iterator;\r
+ typedef typename implementation_defined::insert_commit_data insert_commit_data;\r
+ typedef typename implementation_defined::local_iterator local_iterator;\r
+ typedef typename implementation_defined::const_local_iterator const_local_iterator;\r
+\r
+ private:\r
+ table_type table_;\r
+\r
+ public:\r
+\r
+ //! <b>Requires</b>: buckets must not be being used by any other resource.\r
+ //!\r
+ //! <b>Effects</b>: Constructs an empty iunordered_set, storing a reference\r
+ //! to the bucket array and copies of the hasher and equal functors.\r
+ //! \r
+ //! <b>Complexity</b>: Constant. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor or invocation of Hash or Equal throws. \r
+ //!\r
+ //! <b>Notes</b>: buckets array must be destroyed only after\r
+ //! *this is destroyed. \r
+ iunordered_set( bucket_ptr buckets\r
+ , size_type buckets_len\r
+ , const Hash & hasher = Hash()\r
+ , const Equal &equal = Equal()) \r
+ : table_(buckets, buckets_len, hasher, equal)\r
+ {}\r
+\r
+ //! <b>Requires</b>: buckets must not be being used by any other resource\r
+ //! and Dereferencing iterator must yield an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Constructs an empty iunordered_set and inserts elements from \r
+ //! [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: If N is std::distance(b, e): Average case is O(N)\r
+ //! (with a good hash function and with buckets_len >= N),worst case O(N2).\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor or invocation of Hash or Equal throws. \r
+ //!\r
+ //! <b>Notes</b>: buckets array must be destroyed only after\r
+ //! *this is destroyed. \r
+ template<class Iterator>\r
+ iunordered_set( bucket_ptr buckets\r
+ , size_type buckets_len\r
+ , Iterator b\r
+ , Iterator e\r
+ , const Hash & hasher = Hash()\r
+ , const Equal &equal = Equal()) \r
+ : table_(buckets, buckets_len, hasher, equal)\r
+ { table_.insert_unique(b, e); }\r
+\r
+ //! <b>Effects</b>: Detaches all elements from this. The objects in the iunordered_set \r
+ //! are not deleted (i.e. no destructors are called).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the iunordered_set, if \r
+ //! it's a safe-mode or auto-unlink value. Otherwise constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~iunordered_set() \r
+ {}\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the beginning of the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! Worst case (empty iunordered_set): O(this->bucket_count())\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator begin()\r
+ { return table_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the beginning\r
+ //! of the iunordered_set.\r
+ //!\r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! Worst case (empty iunordered_set): O(this->bucket_count())\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator begin() const\r
+ { return table_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the end of the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator end()\r
+ { return table_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the end of the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator end() const\r
+ { return table_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns the hasher object used by the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If hasher copy-constructor throws.\r
+ hasher hash_function() const\r
+ { return table_.hash_function(); }\r
+\r
+ //! <b>Effects</b>: Returns the key_equal object used by the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If key_equal copy-constructor throws.\r
+ key_equal key_eq() const\r
+ { return table_.key_eq(); }\r
+\r
+ //! <b>Effects</b>: Returns true is the container is empty.\r
+ //! \r
+ //! <b>Complexity</b>: if ConstantTimeSize is false, average constant time\r
+ //! (worst case, with empty() == true): O(this->bucket_count()).\r
+ //! Otherwise constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bool empty() const\r
+ { return table_.empty(); }\r
+\r
+ //! <b>Effects</b>: Returns the number of elements stored in the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to elements contained in *this if\r
+ //! ConstantTimeSize is false. Constant-time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type size() const\r
+ { return table_.size(); }\r
+\r
+ //! <b>Requires</b>: the hasher and the equality function unqualified swap\r
+ //! call should not throw.\r
+ //! \r
+ //! <b>Effects</b>: Swaps the contents of two iunordered_sets.\r
+ //! Swaps also the contained bucket array and equality and hasher functors.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //!\r
+ //! <b>Throws</b>: If the swap() call for the comparison or hash functors\r
+ //! found using ADL throw. Basic guarantee.\r
+ void swap(iunordered_set& other)\r
+ { table_.swap(other.table_); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws. Basic guarantee.\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const iunordered_set &src, Cloner cloner, Destroyer destroyer)\r
+ { table_.clone_from(src.table_, cloner, destroyer); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Tries to inserts value into the iunordered_set.\r
+ //!\r
+ //! <b>Returns</b>: If the value\r
+ //! is not already present inserts it and returns a pair containing the\r
+ //! iterator to the new value and true. If the value is already present\r
+ //! returns a pair containing an iterator to the already present value\r
+ //! and false.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Strong guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ std::pair<iterator, bool> insert(value_type &value)\r
+ { return table_.insert_unique(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //! \r
+ //! <b>Effects</b>: Checks if a value can be inserted in the iunordered_set, using\r
+ //! a user provided key instead of the value itself.\r
+ //!\r
+ //! <b>Returns</b>: If an equivalent value is already present\r
+ //! returns a pair containing an iterator to the already present value\r
+ //! and false. If the value can be inserted returns true in the returned\r
+ //! pair boolean and fills "commit_data" that is meant to be used with\r
+ //! the "insert_commit" function.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //!\r
+ //! <b>Throws</b>: If hasher or key_value_equal throw. Strong guarantee.\r
+ //! \r
+ //! <b>Notes</b>: This function is used to improve performance when constructing\r
+ //! a value_type is expensive: if an equivalent value is already present\r
+ //! the constructed object must be discarded. Many times, the part of the\r
+ //! node that is used to impose the hash or the equality is much cheaper to\r
+ //! construct than the value_type and this function offers the possibility to\r
+ //! use that the part to check if the insertion will be successful.\r
+ //!\r
+ //! If the check is successful, the user can construct the value_type and use\r
+ //! "insert_commit" to insert the object in constant-time.\r
+ //!\r
+ //! "commit_data" remains valid for a subsequent "insert_commit" only if no more\r
+ //! objects are inserted or erased from the iunordered_set.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<iterator, bool> insert_check\r
+ (const KeyType &key, KeyHasher hasher, KeyValueEqual key_value_equal, insert_commit_data &commit_data)\r
+ { return table_.insert_unique_check(key, hasher, key_value_equal, commit_data); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue of type value_type. commit_data\r
+ //! must have been obtained from a previous call to "insert_check".\r
+ //! No objects should have been inserted or erased from the iunordered_set between\r
+ //! the "insert_check" that filled "commit_data" and the call to "insert_commit".\r
+ //! \r
+ //! <b>Effects</b>: Inserts the value in the iunordered_set using the information obtained\r
+ //! from the "commit_data" that a previous "insert_check" filled.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the newly inserted object.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Notes</b>: This function has only sense if a "insert_check" has been\r
+ //! previously executed to fill "commit_data". No value should be inserted or\r
+ //! erased between the "insert_check" and "insert_commit" calls.\r
+ iterator insert_commit(value_type &value, const insert_commit_data &commit_data)\r
+ { return table_.insert_unique_commit(value, commit_data); }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue \r
+ //! of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Equivalent to this->insert(t) for each element in [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(N), where N is std::distance(b, e).\r
+ //! Worst case O(N*this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ template<class Iterator>\r
+ void insert(Iterator b, Iterator e)\r
+ { table_.insert_unique(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed to by i. \r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased element. No destructors are called.\r
+ void erase(const_iterator i)\r
+ { table_.erase(i); }\r
+\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e. \r
+ //! \r
+ //! <b>Complexity</b>: Average case O(std::distance(b, e)),\r
+ //! worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void erase(const_iterator b, const_iterator e)\r
+ { table_.erase(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ size_type erase(const value_type &value)\r
+ { return table_.erase(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements that have the same hash and\r
+ //! compare equal with the given key.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or equal throw. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return table_.erase(key, hasher, equal); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed to by i. \r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators \r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(const_iterator i, Destroyer destroyer)\r
+ { return table_.erase_and_destroy(i, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(std::distance(b, e)),\r
+ //! worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ iterator erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer)\r
+ { return table_.erase_and_destroy(b, e, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { return table_.erase_and_destroy(value, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given key.\r
+ //! according to the comparison functor "equal".\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or key_value_equal throw. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual, class Destroyer>\r
+ size_type erase_and_destroy(const KeyType& key, KeyHasher hasher, KeyValueEqual equal, Destroyer destroyer)\r
+ { return table_.erase_and_destroy(key, hasher, equal, destroyer); }\r
+\r
+ //! <b>Effects</b>: Erases all of the elements. \r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void clear()\r
+ { return table_.clear(); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //! \r
+ //! <b>Effects</b>: Erases all of the elements. \r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ { return table_.clear_and_destroy(destroyer); }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given value\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ size_type count(const value_type &value) const\r
+ { return table_.find(value) != end(); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given key\r
+ //!\r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or equal throw.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual, class Destroyer>\r
+ size_type count(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const\r
+ { return table_.find(key, hasher, equal) != end(); }\r
+\r
+ //! <b>Effects</b>: Finds an iterator to the first element is equal to\r
+ //! "value" or end() if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ iterator find(const value_type &value)\r
+ { return table_.find(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! "key" according to the given hasher and equality functor or end() if\r
+ //! that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or equal throw.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return table_.find(key, hasher, equal); }\r
+\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose key is \r
+ //! "key" or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ const_iterator find(const value_type &value) const\r
+ { return table_.find(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! "key" according to the given hasher and equality functor or end() if\r
+ //! that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or equal throw.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ const_iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const\r
+ { return table_.find(key, equal); }\r
+\r
+ //! <b>Effects</b>: Returns a range containing all elements with values equivalent\r
+ //! to value. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ std::pair<iterator,iterator> equal_range(const value_type &value)\r
+ { return table_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Returns a range containing all elements with equivalent\r
+ //! keys. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or the equal throw.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return table_.equal_range(key, hasher, equal); }\r
+\r
+ //! <b>Effects</b>: Returns a range containing all elements with values equivalent\r
+ //! to value. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const value_type &value) const\r
+ { return table_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Returns a range containing all elements with equivalent\r
+ //! keys. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the hasher or equal throw.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const\r
+ { return table_.equal_range(key, equal); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the iunordered_set\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the internal hash function throws.\r
+ iterator current(value_type &value)\r
+ { return table_.current(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the\r
+ //! iunordered_set that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the internal hash function throws.\r
+ const_iterator current(const value_type &value) const\r
+ { return table_.current(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid local_iterator i belonging to the iunordered_set\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static local_iterator current_local(value_type &value)\r
+ { return table_type::current_local(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_set of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_local_iterator i belonging to\r
+ //! the iunordered_set that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_local_iterator current_local(const value_type &value)\r
+ { return table_type::current_local(value); }\r
+\r
+ //! <b>Effects</b>: Returns the number of buckets passed in the constructor\r
+ //! or the last rehash function.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type bucket_count() const\r
+ { return table_.bucket_count(); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns the number of elements in the nth bucket.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type bucket_size(size_type n)\r
+ { return table_.bucket_size(n); }\r
+\r
+ //! <b>Effects</b>: Returns the index of the bucket in which elements\r
+ //! with keys equivalent to k would be found, if any such element existed.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the hash functor throws.\r
+ //!\r
+ //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).\r
+ size_type bucket(const key_type& k)\r
+ { return table_.bucket(k); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! <b>Effects</b>: Returns the index of the bucket in which elements\r
+ //! with keys equivalent to k would be found, if any such element existed.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If hasher throws.\r
+ //!\r
+ //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).\r
+ template<class KeyType, class KeyHasher>\r
+ size_type bucket(const KeyType& k, KeyHasher hasher)\r
+ { return table_.bucket(k, hasher); }\r
+\r
+ //! <b>Effects</b>: Returns the bucket array pointer passed in the constructor\r
+ //! or the last rehash function.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bucket_ptr bucket_pointer() const\r
+ { return table_.bucket_pointer(); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a local_iterator pointing to the beginning\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ local_iterator begin(size_type n)\r
+ { return table_.begin(n); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_local_iterator pointing to the beginning\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ const_local_iterator begin(size_type n) const\r
+ { return table_.begin(n); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a local_iterator pointing to the end\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ local_iterator end(size_type n)\r
+ { return table_.end(n); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_local_iterator pointing to the end\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ const_local_iterator end(size_type n) const\r
+ { return table_.end(n); }\r
+\r
+ //! <b>Requires</b>: new_buckets must be a pointer to a new bucket array\r
+ //! or the same as the old bucket array. new_size is the length of the\r
+ //! the array pointed by new_buckets. If new_buckets == this->bucket_pointer()\r
+ //! n can be bigger or smaller than this->bucket_count().\r
+ //!\r
+ //! <b>Effects</b>: Updates the internal reference with the new bucket erases\r
+ //! the values from the old bucket and inserts then in the new one. \r
+ //! \r
+ //! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.\r
+ //! \r
+ //! <b>Throws</b>: If the hasher functor throws. Basic guarantee.\r
+ void rehash(bucket_ptr new_buckets, size_type new_size)\r
+ { table_.rehash(new_buckets, new_size); }\r
+\r
+ //! <b>Effects</b>: Returns the nearest new bucket count optimized for\r
+ //! the container that is bigger than n. This suggestion can be used\r
+ //! to create bucket arrays with a size that will usually improve\r
+ //! container's performance. If such value does not exist, the \r
+ //! higher possible value is returned.\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static size_type suggested_upper_bucket_count(size_type n)\r
+ { return table_type::suggested_upper_bucket_count(n); }\r
+\r
+ //! <b>Effects</b>: Returns the nearest new bucket count optimized for\r
+ //! the container that is smaller than n. This suggestion can be used\r
+ //! to create bucket arrays with a size that will usually improve\r
+ //! container's performance. If such value does not exist, the \r
+ //! lower possible value is returned.\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static size_type suggested_lower_bucket_count(size_type n)\r
+ { return table_type::suggested_lower_bucket_count(n); }\r
+};\r
+\r
+//! The class template iunordered_multiset is an intrusive container, that mimics most of \r
+//! the interface of std::tr1::unordered_multiset as described in the C++ TR1.\r
+//!\r
+//! iunordered_multiset is a pseudo-intrusive container: each object to be stored in the\r
+//! container must contain a proper hook, but the container also needs\r
+//! additional auxiliary memory to work: iunordered_multiset needs a pointer to an array\r
+//! of type `bucket_type` to be passed in the constructor. This bucket array must\r
+//! have at least the same lifetime as the container. This makes the use of\r
+//! iunordered_multiset more complicated than purely intrusive containers.\r
+//! `bucket_type` is default-constructible, copyable and assignable\r
+//!\r
+//! The template parameter ValueTraits is called "value traits". It stores\r
+//! information and operations about the type to be stored in the container.\r
+//!\r
+//! The template parameter Hash is a unary function object that take an argument\r
+//! of type ValueTraits::value_type and returns a value of type std::size_t.\r
+//!\r
+//! The template parameter Equal is a binary predicate that takes two arguments of\r
+//! type ValueTraits::value_type. Equal is an equivalence relation.\r
+//!\r
+//! If the user specifies ConstantTimeSize as "true", a member of type SizeType\r
+//! will be embedded in the class, that will keep track of the number of stored objects.\r
+//! This will allow constant-time O(1) size() member, instead of default O(N) size.\r
+//!\r
+//! iunordered_multiset only provides forward iterators but it provides 4 iterator types:\r
+//! iterator and const_iterator to navigate through the whole container and\r
+//! local_iterator and const_local_iterator to navigate through the values\r
+//! stored in a single bucket. Local iterators are faster and smaller.\r
+//!\r
+//! It's not recommended to use non ConstantTimeSize iunordered_multisets because several\r
+//! key functions, like "empty()", become non-constant time functions. Non\r
+//! ConstantTimeSize iunordered_multisets are mainly provided to support auto-unlink hooks.\r
+//!\r
+//! iunordered_multiset, unlike std::unordered_set, does not make automatic rehashings nor\r
+//! offers functions related to a load factor. Rehashing can be explicitly requested\r
+//! and the user must provide a new bucket array that will be used from that moment.\r
+//!\r
+//! Since no automatic rehashing is done, iterators are never invalidated when\r
+//! inserting or erasing elements. Iterators are only invalidated when rehasing.\r
+template< class ValueTraits\r
+ , class Hash = boost::hash<typename ValueTraits::value_type>\r
+ , class Equal = std::equal_to<typename ValueTraits::value_type>\r
+ , bool ConstantTimeSize = true\r
+ , class SizeType = std::size_t\r
+ >\r
+class iunordered_multiset\r
+{\r
+ private:\r
+ typedef detail::ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType> table_type;\r
+\r
+ //! This class is\r
+ //! non-copyable\r
+ iunordered_multiset (const iunordered_multiset&);\r
+\r
+ //! This class is\r
+ //! non-assignable\r
+ iunordered_multiset &operator =(const iunordered_multiset&);\r
+\r
+ typedef table_type implementation_defined;\r
+\r
+ public:\r
+ typedef typename ValueTraits::value_type value_type;\r
+ typedef typename ValueTraits::pointer pointer;\r
+ typedef typename ValueTraits::const_pointer const_pointer;\r
+ typedef value_type& reference;\r
+ typedef const value_type& const_reference;\r
+ typedef SizeType size_type;\r
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;\r
+ typedef value_type key_type;\r
+ typedef Equal key_equal;\r
+ typedef Hash hasher;\r
+ typedef typename implementation_defined::bucket_type bucket_type;\r
+ typedef typename boost::pointer_to_other<pointer, bucket_type>::type bucket_ptr;\r
+ typedef typename implementation_defined::iterator iterator;\r
+ typedef typename implementation_defined::const_iterator const_iterator;\r
+ typedef typename implementation_defined::insert_commit_data insert_commit_data;\r
+ typedef typename implementation_defined::local_iterator local_iterator;\r
+ typedef typename implementation_defined::const_local_iterator const_local_iterator;\r
+\r
+ private:\r
+ table_type table_;\r
+\r
+ public:\r
+\r
+ //! <b>Requires</b>: buckets must not be being used by any other resource.\r
+ //!\r
+ //! <b>Effects</b>: Constructs an empty iunordered_multiset, storing a reference\r
+ //! to the bucket array and copies of the hasher and equal functors.\r
+ //! \r
+ //! <b>Complexity</b>: Constant. \r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor or invocation of Hash or Equal throws. \r
+ //!\r
+ //! <b>Notes</b>: buckets array must be destroyed only after\r
+ //! *this is destroyed. \r
+ iunordered_multiset ( bucket_ptr buckets\r
+ , size_type buckets_len\r
+ , const Hash & hasher = Hash()\r
+ , const Equal &equal = Equal()) \r
+ : table_(buckets, buckets_len, hasher, equal)\r
+ {}\r
+\r
+ //! <b>Requires</b>: buckets must not be being used by any other resource\r
+ //! and Dereferencing iterator must yield an lvalue of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Constructs an empty iunordered_multiset and inserts elements from \r
+ //! [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: If N is std::distance(b, e): Average case is O(N)\r
+ //! (with a good hash function and with buckets_len >= N),worst case O(N2).\r
+ //! \r
+ //! <b>Throws</b>: If value_traits::node_traits::node\r
+ //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)\r
+ //! or the copy constructor or invocation of Hash or Equal throws. \r
+ //!\r
+ //! <b>Notes</b>: buckets array must be destroyed only after\r
+ //! *this is destroyed.\r
+ template<class Iterator>\r
+ iunordered_multiset ( bucket_ptr buckets\r
+ , size_type buckets_len\r
+ , Iterator b\r
+ , Iterator e\r
+ , const Hash & hasher = Hash()\r
+ , const Equal &equal = Equal()) \r
+ : table_(buckets, buckets_len, hasher, equal)\r
+ { table_.insert_equal(b, e); }\r
+\r
+ //! <b>Effects</b>: Detaches all elements from this. The objects in the iunordered_multiset \r
+ //! are not deleted (i.e. no destructors are called).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the iunordered_multiset, if \r
+ //! it's a safe-mode or auto-unlink value. Otherwise constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~iunordered_multiset() \r
+ {}\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the beginning of the iunordered_multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! Worst case (empty iunordered_multiset): O(this->bucket_count())\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator begin()\r
+ { return table_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the beginning\r
+ //! of the iunordered_multiset.\r
+ //!\r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! Worst case (empty iunordered_multiset): O(this->bucket_count())\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator begin() const\r
+ { return table_.begin(); }\r
+\r
+ //! <b>Effects</b>: Returns an iterator pointing to the end of the iunordered_multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iterator end()\r
+ { return table_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns a const_iterator pointing to the end of the iunordered_multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_iterator end() const\r
+ { return table_.end(); }\r
+\r
+ //! <b>Effects</b>: Returns the hasher object used by the iunordered_set.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If hasher copy-constructor throws.\r
+ hasher hash_function() const\r
+ { return table_.hash_function(); }\r
+\r
+ //! <b>Effects</b>: Returns the key_equal object used by the iunordered_multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If key_equal copy-constructor throws.\r
+ key_equal key_eq() const\r
+ { return table_.key_eq(); }\r
+\r
+ //! <b>Effects</b>: Returns true is the container is empty.\r
+ //! \r
+ //! <b>Complexity</b>: if ConstantTimeSize is false, average constant time\r
+ //! (worst case, with empty() == true): O(this->bucket_count()).\r
+ //! Otherwise constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bool empty() const\r
+ { return table_.empty(); }\r
+\r
+ //! <b>Effects</b>: Returns the number of elements stored in the iunordered_multiset.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to elements contained in *this if\r
+ //! ConstantTimeSize is false. Constant-time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type size() const\r
+ { return table_.size(); }\r
+\r
+ //! <b>Requires</b>: the hasher and the equality function unqualified swap\r
+ //! call should not throw.\r
+ //! \r
+ //! <b>Effects</b>: Swaps the contents of two iunordered_multisets.\r
+ //! Swaps also the contained bucket array and equality and hasher functors.\r
+ //!\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //!\r
+ //! <b>Throws</b>: If the swap() call for the comparison or hash functors\r
+ //! found using ADL throw. Basic guarantee.\r
+ void swap(iunordered_multiset& other)\r
+ { table_.swap(other.table_); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements from *this\r
+ //! calling Destroyer::operator()(pointer), clones all the \r
+ //! elements from src calling Cloner::operator()(const value_type &)\r
+ //! and inserts them on *this.\r
+ //!\r
+ //! If cloner throws, all cloned elements are unlinked and destroyed\r
+ //! calling Destroyer::operator()(pointer).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to erased plus inserted elements.\r
+ //! \r
+ //! <b>Throws</b>: If cloner throws.\r
+ template <class Cloner, class Destroyer>\r
+ void clone_from(const iunordered_multiset &src, Cloner cloner, Destroyer destroyer)\r
+ { table_.clone_from(src.table_, cloner, destroyer); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue\r
+ //! \r
+ //! <b>Effects</b>: Inserts value into the iunordered_multiset.\r
+ //!\r
+ //! <b>Returns</b>: An iterator to the new inserted value.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Strong guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ iterator insert(value_type &value)\r
+ { return table_.insert_equal(value); }\r
+\r
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue \r
+ //! of type value_type.\r
+ //! \r
+ //! <b>Effects</b>: Equivalent to this->insert(t) for each element in [b, e).\r
+ //! \r
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the \r
+ //! size of the range. However, it is linear in N if the range is already sorted \r
+ //! by value_comp().\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Does not affect the validity of iterators and references.\r
+ //! No copy-constructors are called.\r
+ template<class Iterator>\r
+ void insert(Iterator b, Iterator e)\r
+ { table_.insert_equal(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases the element pointed to by i. \r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased element. No destructors are called.\r
+ void erase(const_iterator i)\r
+ { table_.erase(i); }\r
+\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e. \r
+ //! \r
+ //! <b>Complexity</b>: Average case O(std::distance(b, e)),\r
+ //! worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void erase(const_iterator b, const_iterator e)\r
+ { table_.erase(b, e); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ size_type erase(const value_type &value)\r
+ { return table_.erase(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements that have the same hash and\r
+ //! compare equal with the given key.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the hasher or the equal functors throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return table_.erase(key, hasher, equal); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the element pointed to by i. \r
+ //! Destroyer::operator()(pointer) is called for the removed element.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators \r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ void erase_and_destroy(const_iterator i, Destroyer destroyer)\r
+ { table_.erase_and_destroy(i, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases the range pointed to by b end e.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(std::distance(b, e)),\r
+ //! worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class Destroyer>\r
+ void erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer)\r
+ { table_.erase_and_destroy(b, e, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given value.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+ { return table_.erase_and_destroy(value, destroyer); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: Erases all the elements with the given key.\r
+ //! according to the comparison functor "equal".\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //!\r
+ //! <b>Returns</b>: The number of erased elements.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)).\r
+ //! Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If hasher or equal throw. Basic guarantee.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators\r
+ //! to the erased elements.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual, class Destroyer>\r
+ size_type erase_and_destroy(const KeyType& key, KeyHasher hasher, KeyValueEqual equal, Destroyer destroyer)\r
+ { return table_.erase_and_destroy(key, hasher, equal, destroyer); }\r
+\r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ void clear()\r
+ { return table_.clear(); }\r
+\r
+ //! <b>Requires</b>: Destroyer::operator()(pointer) shouldn't throw.\r
+ //! \r
+ //! <b>Effects</b>: Erases all the elements of the container.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements on the container.\r
+ //! Destroyer::operator()(pointer) is called for the removed elements.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: Invalidates the iterators (but not the references)\r
+ //! to the erased elements. No destructors are called.\r
+ template<class Destroyer>\r
+ void clear_and_destroy(Destroyer destroyer)\r
+ { return table_.clear_and_destroy(destroyer); }\r
+\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given key\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ size_type count(const value_type &value) const\r
+ { return table_.count(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Returns the number of contained elements with the given key\r
+ //!\r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual, class Destroyer>\r
+ size_type count(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const\r
+ { return table_.count(key, hasher, equal); }\r
+\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose value is \r
+ //! "value" or end() if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ iterator find(const value_type &value)\r
+ { return table_.find(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! "key" according to the given hasher and equality functor or end() if\r
+ //! that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return table_.find(key, hasher, equal); }\r
+\r
+ //! <b>Effects</b>: Finds a const_iterator to the first element whose key is \r
+ //! "key" or end() if that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ const_iterator find(const value_type &value) const\r
+ { return table_.find(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Finds an iterator to the first element whose key is \r
+ //! "key" according to the given hasher and equality functor or end() if\r
+ //! that element does not exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ const_iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const\r
+ { return table_.find(key, equal); }\r
+\r
+ //! <b>Effects</b>: Returns a range containing all elements with values equivalent\r
+ //! to value. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ std::pair<iterator,iterator> equal_range(const value_type &value)\r
+ { return table_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Returns a range containing all elements with equivalent\r
+ //! keys. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+ { return table_.equal_range(key, hasher, equal); }\r
+\r
+ //! <b>Effects</b>: Returns a range containing all elements with values equivalent\r
+ //! to value. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const value_type &value) const\r
+ { return table_.equal_range(value); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! "key_value_equal" must be a equality function that induces \r
+ //! the same equality as key_equal. The difference is that\r
+ //! "key_value_equal" compares an arbitrary key with the contained values.\r
+ //!\r
+ //! <b>Effects</b>: Returns a range containing all elements with equivalent\r
+ //! keys. Returns std::make_pair(this->end(), this->end()) if no such \r
+ //! elements exist.\r
+ //! \r
+ //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).\r
+ //! \r
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.\r
+ //!\r
+ //! <b>Note</b>: This function is used when constructing a value_type\r
+ //! is expensive and the value_type can be compared with a cheaper\r
+ //! key type. Usually this key is part of the value_type.\r
+ template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+ std::pair<const_iterator, const_iterator>\r
+ equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const\r
+ { return table_.equal_range(key, equal); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_multiset of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the iunordered_multiset\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the hash function throws.\r
+ iterator current(value_type &value)\r
+ { return table_.current(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_multiset of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the\r
+ //! iunordered_multiset that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the hash function throws.\r
+ const_iterator current(const value_type &value) const\r
+ { return table_.current(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_multiset of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid local_iterator i belonging to the iunordered_multiset\r
+ //! that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static local_iterator current_local(value_type &value)\r
+ { return table_type::current_local(value); }\r
+\r
+ //! <b>Requires</b>: value must be an lvalue and shall be in a iunordered_multiset of\r
+ //! appropriate type. Otherwise the behavior is undefined.\r
+ //! \r
+ //! <b>Effects</b>: Returns: a valid const_local_iterator i belonging to\r
+ //! the iunordered_multiset that points to the value\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_local_iterator current_local(const value_type &value)\r
+ { return table_type::current_local(value); }\r
+\r
+ //! <b>Effects</b>: Returns the number of buckets passed in the constructor\r
+ //! or the last rehash function.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type bucket_count() const\r
+ { return table_.bucket_count(); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns the number of elements in the nth bucket.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ size_type bucket_size(size_type n)\r
+ { return table_.bucket_size(n); }\r
+\r
+ //! <b>Effects</b>: Returns the index of the bucket in which elements\r
+ //! with keys equivalent to k would be found, if any such element existed.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the hash functor throws.\r
+ //!\r
+ //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).\r
+ size_type bucket(const key_type& k)\r
+ { return table_.bucket(k); }\r
+\r
+ //! <b>Requires</b>: "hasher" must be a hash function that induces \r
+ //! the same hash values as the stored hasher. The difference is that\r
+ //! "hasher" hashes the given key instead of the value_type.\r
+ //!\r
+ //! <b>Effects</b>: Returns the index of the bucket in which elements\r
+ //! with keys equivalent to k would be found, if any such element existed.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: If the hash functor throws.\r
+ //!\r
+ //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).\r
+ template<class KeyType, class KeyHasher>\r
+ size_type bucket(const KeyType& k, const KeyHasher &hasher)\r
+ { return table_.bucket(k, hasher); }\r
+\r
+ //! <b>Effects</b>: Returns the bucket array pointer passed in the constructor\r
+ //! or the last rehash function.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ bucket_ptr bucket_pointer() const\r
+ { return table_.bucket_pointer(); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a local_iterator pointing to the beginning\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ local_iterator begin(size_type n)\r
+ { return table_.begin(n); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_local_iterator pointing to the beginning\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ const_local_iterator begin(size_type n) const\r
+ { return table_.begin(n); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a local_iterator pointing to the end\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ local_iterator end(size_type n)\r
+ { return table_.end(n); }\r
+\r
+ //! <b>Requires</b>: n is in the range [0, this->bucket_count()).\r
+ //!\r
+ //! <b>Effects</b>: Returns a const_local_iterator pointing to the end\r
+ //! of the sequence stored in the bucket n.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range\r
+ //! containing all of the elements in the nth bucket. \r
+ const_local_iterator end(size_type n) const\r
+ { return table_.end(n); }\r
+\r
+ //! <b>Requires</b>: new_buckets must be a pointer to a new bucket array\r
+ //! or the same as the old bucket array. new_size is the length of the\r
+ //! the array pointed by new_buckets. If new_buckets == this->bucket_pointer()\r
+ //! n can be bigger or smaller than this->bucket_count().\r
+ //!\r
+ //! <b>Effects</b>: Updates the internal reference with the new bucket erases\r
+ //! the values from the old bucket and inserts then in the new one. \r
+ //! \r
+ //! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.\r
+ //! \r
+ //! <b>Throws</b>: If the hasher functor throws.\r
+ void rehash(bucket_ptr new_buckets, size_type new_size)\r
+ { table_.rehash(new_buckets, new_size); }\r
+\r
+ //! <b>Effects</b>: Returns the nearest new bucket count optimized for\r
+ //! the container that is bigger than n. This suggestion can be used\r
+ //! to create bucket arrays with a size that will usually improve\r
+ //! container's performance. If such value does not exist, the \r
+ //! higher possible value is returned.\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static size_type suggested_upper_bucket_count(size_type n)\r
+ { return table_type::suggested_upper_bucket_count(n); }\r
+\r
+ //! <b>Effects</b>: Returns the nearest new bucket count optimized for\r
+ //! the container that is smaller than n. This suggestion can be used\r
+ //! to create bucket arrays with a size that will usually improve\r
+ //! container's performance. If such value does not exist, the \r
+ //! lower possible value is returned.\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static size_type suggested_lower_bucket_count(size_type n)\r
+ { return table_type::suggested_lower_bucket_count(n); }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_IHASHSET_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_IHASHSET_HOOK_HPP\r
+#define BOOST_INTRUSIVE_IHASHSET_HOOK_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <boost/intrusive/detail/utilities.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/intrusive/islist_hook.hpp>\r
+#include <boost/intrusive/linking_policy.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <stdexcept>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! Derive a class from iunordered_set_base_hook in order to store objects in \r
+//! in an iunordered_set/iunordered_multi_set. iunordered_set_base_hook holds the data necessary to maintain \r
+//! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for iunordered_set/iunordered_multi_set.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one iunordered_set_base_hook, then each iunordered_set_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second boolean template parameter will activate the safe-mode checks\r
+//! if it's configured as "true".\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the iunordered_set/iunordered_multi_set configured from this hook.\r
+template<typename Tag, bool SafeMode = true, class VoidPointer = void*>\r
+class iunordered_set_base_hook\r
+{\r
+ typedef islist_base_hook<Tag, SafeMode, VoidPointer> IsListHook;\r
+ IsListHook m_islisthook;\r
+ typedef IsListHook implementation_defined;\r
+\r
+ public:\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+ typedef typename implementation_defined::node_traits node_traits;\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iunordered_set_base_hook\r
+ <Tag, SafeMode, VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ iunordered_set_base_hook()\r
+ : m_islisthook()\r
+ {}\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iunordered_set_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ iunordered_set_base_hook(const iunordered_set_base_hook &other)\r
+ : m_islisthook(other.m_islisthook)\r
+ {}\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iunordered_set_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work. "swap" can be used to emulate\r
+ //! move-semantics.\r
+ iunordered_set_base_hook& operator=(const iunordered_set_base_hook &other)\r
+ { m_islisthook = other.m_islisthook; return *this; }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an iunordered_set/iunordered_multiset an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ ~iunordered_set_base_hook() \r
+ {}\r
+\r
+ //! <b>Precondition</b>: The hook must be in safe-mode.\r
+ //!\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant\r
+ bool linked() const \r
+ { return m_islisthook.linked(); }\r
+\r
+ //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset. \r
+ //! The template argument T defines the class type stored in iunordered_set/iunordered_multiset. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ node_ptr to_node_ptr()\r
+ { return m_islisthook.to_node_ptr(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_node_ptr to_node_ptr() const\r
+ { return m_islisthook.to_node_ptr(); }\r
+};\r
+\r
+\r
+//! Derive a class from iunordered_set_auto_base_hook in order to store objects in an \r
+//! iunordered_set/iunordered_multi_set. iunordered_set_auto_base_hook holds the data necessary to maintain the \r
+//! unordered_set and provides an appropriate value_traits class for iunordered_set/iunordered_multi_set.\r
+//!\r
+//! The difference between iunordered_set_auto_base_hook and iunordered_set_base_hook is that\r
+//! iunordered_set_auto_base_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! iunordered_set_auto_base_hook can only be used with non constant-time iunordered_set/iunordered_multi_sets.\r
+//! \r
+//! The first integer template argument defines a tag to identify the node. \r
+//! The same tag value can be used in different classes, but if a class is \r
+//! derived from more than one iunordered_set_auto_base_hook, then each iunordered_set_auto_base_hook needs its \r
+//! unique tag.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the iunordered_set/unordered_multi_set configured from this hook.\r
+template<typename Tag, class VoidPointer = void*>\r
+class iunordered_set_auto_base_hook\r
+{\r
+ typedef islist_auto_base_hook<Tag, VoidPointer> IsListHook;\r
+ IsListHook m_islisthook;\r
+ typedef IsListHook implementation_defined;\r
+\r
+ public:\r
+ enum { linking_policy = auto_unlink };\r
+ typedef typename implementation_defined::node_traits node_traits;\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iunordered_set_auto_base_hook\r
+ <Tag,VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iunordered_set_auto_base_hook()\r
+ : m_islisthook()\r
+ {}\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iunordered_set_auto_base_hook(const iunordered_set_auto_base_hook &other)\r
+ : m_islisthook(other.m_islisthook)\r
+ {}\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iunordered_set_auto_base_hook& operator=(const iunordered_set_auto_base_hook &other)\r
+ { m_islisthook = other.m_islisthook; return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iunordered_set_auto_base_hook() \r
+ {}\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return m_islisthook.linked(); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ { return m_islisthook.unlink(); }\r
+\r
+ //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset. \r
+ //! The template argument T defines the class type stored in iunordered_set/iunordered_multiset. Objects \r
+ //! of type T and of types derived from T can be stored. T doesn't need to be \r
+ //! copy-constructible or assignable.\r
+ template<class T>\r
+ struct value_traits\r
+ : detail::derivation_value_traits<T, this_type, Tag>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ node_ptr to_node_ptr()\r
+ { return m_islisthook.to_node_ptr(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_node_ptr to_node_ptr() const\r
+ { return m_islisthook.to_node_ptr(); }\r
+};\r
+\r
+\r
+//! Put a public data member iunordered_set_member_hook in order to store objects of this class in\r
+//! an iunordered_set/iunordered_multi_set. iunordered_set_member_hook holds the data necessary for maintaining the\r
+//! unordered_set/unordered_multi_set and provides an appropriate value_traits class for iunordered_set/iunordered_multi_set.\r
+//! \r
+//! The template argument T defines the class type stored in iunordered_set/iunordered_multi_set. Objects of \r
+//! type T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//! \r
+//! The second boolean template argument SafeMode controls initializes\r
+//! the node to a safe state in the constructor and asserts if the node is destroyed\r
+//! or it's assigned but it's still inserted in a iunordered_set/iunordered_multi_set.\r
+//!\r
+//! The third argument is the pointer type that will be used internally in the hook\r
+//! and the iunordered_set/iunordered_multi_set configured from this hook.\r
+template<class T, bool SafeMode = true, class VoidPointer = void*>\r
+class iunordered_set_member_hook\r
+{\r
+ typedef islist_member_hook<T, SafeMode, VoidPointer> IsListHook;\r
+ IsListHook m_islisthook;\r
+ typedef IsListHook implementation_defined;\r
+\r
+ public:\r
+ enum { linking_policy = SafeMode? safe_mode_link : normal_link};\r
+ typedef typename implementation_defined::node_traits node_traits;\r
+ typedef typename node_traits::node node;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef iunordered_set_member_hook\r
+ <T, SafeMode, VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ public:\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iunordered_set_member_hook()\r
+ : m_islisthook()\r
+ {}\r
+\r
+ //! <b>Effects</b>: If SafeMode is true initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iunordered_set_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iunordered_set_member_hook(const iunordered_set_member_hook &other)\r
+ : m_islisthook(other.m_islisthook)\r
+ {}\r
+\r
+ //! <b>Effects</b>: If SafeMode is true, an assertion is raised\r
+ //! if the node is still linked. After that, the node is initialized\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iunordered_set_member_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iunordered_set_member_hook& operator=(const iunordered_set_member_hook &other) \r
+ { m_islisthook = other.m_islisthook; return *this; }\r
+\r
+ //! <b>Effects</b>: If SafeMode is set to false, the destructor does\r
+ //! nothing (ie. no code is generated). If SafeMode is true and the\r
+ //! object is stored in an iunordered_set/iunordered_multiset an assertion is raised.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iunordered_set_member_hook() \r
+ {}\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return m_islisthook.linked(); }\r
+\r
+ //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ { m_islisthook.unlink(); }\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ node_ptr to_node_ptr()\r
+ { return m_islisthook.to_node_ptr(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ const_node_ptr to_node_ptr() const\r
+ { return m_islisthook.to_node_ptr(); }\r
+};\r
+\r
+//! Put a public data member iunordered_set_auto_member_hook in order to store objects of this class in\r
+//! an iunordered_set/iunordered_multiset. iunordered_set_auto_member_hook holds the data necessary for maintaining the list and \r
+//! provides an appropriate value_traits class for iunordered_set/iunordered_multiset.\r
+//!\r
+//! The difference between iunordered_set_auto_member_hook and iunordered_set_member_hook is that\r
+//! iunordered_set_auto_member_hook removes itself automatically from the container\r
+//! in the assignment operator and the destructor. It also provides a new\r
+//! "unlink" method so that the user can unlink its class without using\r
+//! the container.\r
+//!\r
+//! iunordered_set_auto_member_hook can only be used with non constant-time iunordered_sets/iunordered_multisets.\r
+//! \r
+//! The first template argument T defines the class type stored in iunordered_set/iunordered_multiset. Objects of\r
+//! type T and of types derived from T can be stored. T doesn't need to be \r
+//! copy-constructible or assignable.\r
+//!\r
+//! The second argument is the pointer type that will be used internally in the hook\r
+//! and the iunordered_set/iunordered_multiset configured from this hook.\r
+template<class T, class VoidPointer = void*>\r
+class iunordered_set_auto_member_hook\r
+{\r
+ typedef islist_auto_member_hook<T, VoidPointer> IsListHook;\r
+ IsListHook m_islisthook;\r
+ typedef IsListHook implementation_defined;\r
+\r
+ public:\r
+ enum { linking_policy = auto_unlink };\r
+ typedef typename implementation_defined::node_traits node_traits;\r
+ typedef typename node_traits::node node;\r
+ typedef iunordered_set_auto_member_hook\r
+ <T, VoidPointer> this_type;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, node>::type node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const node>::type const_node_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, this_type>::type this_type_ptr;\r
+ typedef typename boost::pointer_to_other\r
+ <VoidPointer, const this_type>::type const_this_type_ptr;\r
+\r
+ public:\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ iunordered_set_auto_member_hook()\r
+ : m_islisthook()\r
+ {}\r
+\r
+ //! <b>Effects</b>: Initializes the node\r
+ //! to an unlinked state. The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing a copy-constructor\r
+ //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iunordered_set_auto_member_hook(const iunordered_set_auto_member_hook &other)\r
+ : m_islisthook(other.m_islisthook)\r
+ {}\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! The argument is ignored.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ //! \r
+ //! <b>Rationale</b>: Providing an assignment operator \r
+ //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the \r
+ //! user to do some additional work.\r
+ iunordered_set_auto_member_hook& operator=(const iunordered_set_auto_member_hook &other)\r
+ { m_islisthook = other.m_islisthook; return *this; }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ ~iunordered_set_auto_member_hook() \r
+ {}\r
+\r
+ //! <b>Returns</b>: true, if the node belongs to a container, false\r
+ //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current \r
+ //! will return a valid iterator. \r
+ //!\r
+ //! <b>Complexity</b>: Constant \r
+ bool linked() const \r
+ { return m_islisthook.linked(); }\r
+\r
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ void unlink()\r
+ { return m_islisthook.unlink(); }\r
+\r
+ //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset. \r
+ //! The template argument is a pointer to member pointing to the node in \r
+ //! the class. Objects of type T and of types derived from T can be stored. \r
+ //! T doesn't need to be copy-constructible or assignable.\r
+ template<this_type T::* M>\r
+ struct value_traits\r
+ : detail::member_value_traits<T, this_type, M>\r
+ {};\r
+\r
+ //! <b>Effects</b>: Converts a pointer to a node into\r
+ //! a pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static this_type_ptr to_hook_ptr(node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Converts a const pointer to a node stored in a container into\r
+ //! a const pointer to the hook that holds that node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing. \r
+ static const_this_type_ptr to_hook_ptr(const_node_ptr p)\r
+ {\r
+ using boost::get_pointer;\r
+ return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));\r
+ }\r
+\r
+ //! <b>Effects</b>: Returns a pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ node_ptr to_node_ptr()\r
+ { return m_islisthook.to_node_ptr(); }\r
+\r
+ //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ const_node_ptr to_node_ptr() const\r
+ { return m_islisthook.to_node_ptr(); }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_IHASHSET_HOOK_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP\r
+#define BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//!This enumeration defines the type of value_traits that can be defined\r
+//!for Boost.Intrusive containers\r
+enum linking_policy{\r
+ //!If this linking policy is specified in a value_traits class\r
+ //!as the linking_policy, containers\r
+ //!configured with such value_traits won't set the hooks\r
+ //!of the erased values to a default state. Containers also won't\r
+ //!check that the hooks of the new values are default initialized.\r
+ normal_link,\r
+\r
+ //!If this linking policy is specified in a value_traits class\r
+ //!as the linking_policy, containers\r
+ //!configured with such value_traits will set the hooks\r
+ //!of the erased values to a default state. Containers also will\r
+ //!check that the hooks of the new values are default initialized.\r
+ safe_mode_link,\r
+\r
+ //!Same as "safe_mode_link" but the user type is an auto-unlink\r
+ //!type, so the containers with constant-time size features won't be\r
+ //!compatible with value_traits configured with this policy.\r
+ //!Containers also know that the a value can be silently erased from\r
+ //!the container without using any function provided by the containers.\r
+ auto_unlink\r
+};\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#endif //BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_LIST_ALGORITHMS_HPP\r
+#define BOOST_INTRUSIVE_LIST_ALGORITHMS_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <iterator>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <cstddef>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! list_algorithms provides basic algorithms to manipulate nodes\r
+//! forming a circular doubly linked list. An empty circular list is formed by a node\r
+//! whose pointers point to itself.\r
+//!\r
+//! list_algorithms is configured with a NodeTraits class, which encapsulates the\r
+//! information about the node to be manipulated. NodeTraits must support the\r
+//! following interface:\r
+//!\r
+//! <b>Typedefs</b>:\r
+//!\r
+//! <tt>node</tt>: The type of the node that forms the circular list\r
+//!\r
+//! <tt>node_ptr</tt>: A pointer to a node\r
+//!\r
+//! <tt>const_node_ptr</tt>: A pointer to a const node\r
+//!\r
+//! <b>Static functions</b>:\r
+//!\r
+//! <tt>static node_ptr get_previous(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_previous(node_ptr n, node_ptr prev);</tt>\r
+//! \r
+//! <tt>static node_ptr get_next(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_next(node_ptr n, node_ptr next);</tt>\r
+template<class NodeTraits>\r
+class list_algorithms\r
+{\r
+ public:\r
+ typedef typename NodeTraits::node_ptr node_ptr;\r
+ typedef typename NodeTraits::const_node_ptr const_node_ptr;\r
+\r
+ //! <b>Effects</b>: Constructs an empty list, making this_node the only\r
+ //! node of the circular list:\r
+ //! <tt>NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node)\r
+ //! == this_node</tt>.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void init(node_ptr this_node)\r
+ {\r
+ NodeTraits::set_next(this_node, this_node);\r
+ NodeTraits::set_previous(this_node, this_node);\r
+ } \r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:\r
+ //! <tt>return NodeTraits::get_next(this_node) == this_node</tt>\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static bool unique(const_node_ptr this_node) \r
+ { return NodeTraits::get_next(this_node) == this_node; }\r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list\r
+ //! is empty, returns 1.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static std::size_t count(const_node_ptr this_node) \r
+ {\r
+ std::size_t result = 0;\r
+ const_node_ptr p = this_node;\r
+ do{\r
+ p = NodeTraits::get_next(p);\r
+ ++result;\r
+ }while (p != this_node);\r
+ return result;\r
+ }\r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Unlinks the node from the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr unlink(node_ptr this_node)\r
+ {\r
+ node_ptr next(NodeTraits::get_next(this_node));\r
+ node_ptr prev(NodeTraits::get_previous(this_node));\r
+ NodeTraits::set_next(prev, next);\r
+ NodeTraits::set_previous(next, prev);\r
+ return next;\r
+ }\r
+\r
+ //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.\r
+ //! \r
+ //! <b>Effects</b>: Unlinks the node [b, e) from the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void unlink(node_ptr b, node_ptr e)\r
+ {\r
+ if (b != e) {\r
+ node_ptr prev(NodeTraits::get_previous(b));\r
+ node_ptr next(NodeTraits::get_next(e));\r
+ NodeTraits::set_previous(next, prev);\r
+ NodeTraits::set_next(prev, next);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: nxt_node must be a node of a circular list.\r
+ //! \r
+ //! <b>Effects</b>: Links this_node before nxt_node in the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void link_before(node_ptr nxt_node, node_ptr this_node)\r
+ {\r
+ node_ptr prev(NodeTraits::get_previous(nxt_node));\r
+ NodeTraits::set_previous(this_node, prev);\r
+ NodeTraits::set_next(prev, this_node);\r
+ NodeTraits::set_previous(nxt_node, this_node);\r
+ NodeTraits::set_next(this_node, nxt_node);\r
+ }\r
+\r
+ //! <b>Requires</b>: prev_node must be a node of a circular list.\r
+ //! \r
+ //! <b>Effects</b>: Links this_node after prev_node in the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void link_after(node_ptr prev_node, node_ptr this_node)\r
+ {\r
+ node_ptr next(NodeTraits::get_next(prev_node));\r
+ NodeTraits::set_previous(this_node, prev_node);\r
+ NodeTraits::set_next(this_node, next);\r
+ NodeTraits::set_previous(next, this_node);\r
+ NodeTraits::set_next(prev_node, this_node);\r
+ }\r
+\r
+ //! <b>Requires</b>: this_node and other_node must be nodes inserted\r
+ //! in circular lists or be empty circular lists.\r
+ //! \r
+ //! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in\r
+ //! other_nodes position in the second circular list and the other_node is inserted\r
+ //! in this_node's position in the first circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void swap_nodes(node_ptr this_node, node_ptr other_node)\r
+ {\r
+ if (other_node == this_node)\r
+ return;\r
+ bool empty1 = unique(this_node);\r
+ bool empty2 = unique(other_node);\r
+\r
+ node_ptr next_this(NodeTraits::get_next(this_node));\r
+ node_ptr prev_this(NodeTraits::get_previous(this_node));\r
+ node_ptr next_other(NodeTraits::get_next(other_node));\r
+ node_ptr prev_other(NodeTraits::get_previous(other_node));\r
+\r
+ //Do the swap\r
+ NodeTraits::set_next(this_node, next_other);\r
+ NodeTraits::set_next(other_node, next_this);\r
+\r
+ NodeTraits::set_previous(this_node, prev_other);\r
+ NodeTraits::set_previous(other_node, prev_this);\r
+\r
+ if (empty2){\r
+ init(this_node);\r
+ }\r
+ else{\r
+ NodeTraits::set_next(prev_other, this_node);\r
+ NodeTraits::set_previous(next_other, this_node);\r
+ }\r
+ if (empty1){\r
+ init(other_node);\r
+ }\r
+ else{\r
+ NodeTraits::set_next(prev_this, other_node);\r
+ NodeTraits::set_previous(next_this, other_node);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.\r
+ //! and p must be a node of a different circular list or may not be an iterator in \r
+ // [b, e).\r
+ //! \r
+ //! <b>Effects</b>: Removes the nodes from [b, e) range from their circular list and inserts\r
+ //! them before p in p's circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void transfer(node_ptr p, node_ptr b, node_ptr e)\r
+ {\r
+ if (b != e) {\r
+ node_ptr prev_p(NodeTraits::get_previous(p));\r
+ node_ptr prev_e(NodeTraits::get_previous(e));\r
+ node_ptr prev_b(NodeTraits::get_previous(b));\r
+ NodeTraits::set_next(prev_e, p);\r
+ NodeTraits::set_previous(p, prev_e);\r
+ NodeTraits::set_next(prev_b, e);\r
+ NodeTraits::set_previous(e, prev_b);\r
+ NodeTraits::set_next(prev_p, b);\r
+ NodeTraits::set_previous(b, prev_p);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: i must a node of a circular list\r
+ //! and p must be a node of a different circular list.\r
+ //! \r
+ //! <b>Effects</b>: Removes the node i from its circular list and inserts\r
+ //! it before p in p's circular list. \r
+ //! If p == i or p == NodeTraits::get_next(i), this function is a null operation.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void transfer(node_ptr p, node_ptr i)\r
+ {\r
+ node_ptr n(NodeTraits::get_next(i));\r
+ if(n != p && i != p){\r
+ node_ptr prev_p(NodeTraits::get_previous(p));\r
+ node_ptr prev_i(NodeTraits::get_previous(i));\r
+ NodeTraits::set_next(prev_p, i);\r
+ NodeTraits::set_previous(i, prev_p);\r
+ NodeTraits::set_next(i, p);\r
+ NodeTraits::set_previous(p, i);\r
+ NodeTraits::set_previous(n, prev_i);\r
+ NodeTraits::set_next(prev_i, n);\r
+\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Reverses the order of elements in the list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear time.\r
+ static void reverse(node_ptr p)\r
+ {\r
+ node_ptr f(NodeTraits::get_next(p));\r
+ node_ptr i(NodeTraits::get_next(f)), e(p);\r
+ \r
+ while(i != e) {\r
+ node_ptr n = i;\r
+ i = NodeTraits::get_next(i);\r
+ transfer(f, n, i);\r
+ f = n;\r
+ }\r
+ }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_LIST_ALGORITHMS_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007.\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+// The internal implementation of red-black trees is based on that of SGI STL\r
+// stl_tree.h file: \r
+//\r
+// Copyright (c) 1996,1997\r
+// Silicon Graphics Computer Systems, Inc.\r
+//\r
+// Permission to use, copy, modify, distribute and sell this software\r
+// and its documentation for any purpose is hereby granted without fee,\r
+// provided that the above copyright notice appear in all copies and\r
+// that both that copyright notice and this permission notice appear\r
+// in supporting documentation. Silicon Graphics makes no\r
+// representations about the suitability of this software for any\r
+// purpose. It is provided "as is" without express or implied warranty.\r
+//\r
+//\r
+// Copyright (c) 1994\r
+// Hewlett-Packard Company\r
+//\r
+// Permission to use, copy, modify, distribute and sell this software\r
+// and its documentation for any purpose is hereby granted without fee,\r
+// provided that the above copyright notice appear in all copies and\r
+// that both that copyright notice and this permission notice appear\r
+// in supporting documentation. Hewlett-Packard Company makes no\r
+// representations about the suitability of this software for any\r
+// purpose. It is provided "as is" without express or implied warranty.\r
+\r
+#ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP\r
+#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <iterator>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <boost/type_traits/alignment_of.hpp>\r
+#include <cstddef>\r
+#include <boost/detail/no_exceptions_support.hpp>\r
+\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! rbtree_algorithms provides basic algorithms to manipulate \r
+//! nodes forming a red-black tree. The insertion and deletion algorithms are
+//! based on those in Cormen, Leiserson, and Rivest, Introduction to Algorithms
+//! (MIT Press, 1990), except that
+//!
+//! (1) the header node is maintained with links not only to the root
+//! but also to the leftmost node of the tree, to enable constant time
+//! begin(), and to the rightmost node of the tree, to enable linear time
+//! performance when used with the generic set algorithms (set_union,
+//! etc.);
+//!
+//! (2) when a node being deleted has two children its successor node is
+//! relinked into its place, rather than copied, so that the only
+//! iterators invalidated are those referring to the deleted node.\r
+//!\r
+//! rbtree_algorithms is configured with a NodeTraits class, which capsulates the\r
+//! information about the node to be manipulated. NodeTraits must support the\r
+//! following interface:\r
+//!\r
+//! <b>Typedefs</b>:\r
+//!\r
+//! <tt>node</tt>: The type of the node that forms the circular list\r
+//!\r
+//! <tt>node_ptr</tt>: A pointer to a node\r
+//!\r
+//! <tt>const_node_ptr</tt>: A pointer to a const node\r
+//!\r
+//! <tt>color</tt>: The type that can store the color of a node\r
+//!\r
+//! <b>Static functions</b>:\r
+//!\r
+//! <tt>static node_ptr get_parent(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt>\r
+//!\r
+//! <tt>static node_ptr get_left(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_left(node_ptr n, node_ptr left);</tt>\r
+//!\r
+//! <tt>static node_ptr get_right(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_right(node_ptr n, node_ptr right);</tt>\r
+//! \r
+//! <tt>static color get_color(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_color(node_ptr n, color c);</tt>\r
+//! \r
+//! <tt>static color black();</tt>\r
+//! \r
+//! <tt>static color red();</tt>\r
+template<class NodeTraits>\r
+class rbtree_algorithms\r
+{\r
+ private:\r
+ typedef typename NodeTraits::node node;\r
+\r
+ public:\r
+ typedef typename NodeTraits::node_ptr node_ptr;\r
+ typedef typename NodeTraits::const_node_ptr const_node_ptr;\r
+ typedef typename NodeTraits::color color;\r
+\r
+ //! This type is the information that will be filled by insert_unique_check\r
+ struct insert_commit_data\r
+ {\r
+ insert_commit_data()\r
+ : link_left(false)\r
+ , node(0)\r
+ {}\r
+ bool link_left;\r
+ node_ptr node;\r
+ };\r
+\r
+ //! <b>Requires</b>: header1 and header2 must be the header nodes\r
+ //! of two trees.\r
+ //! \r
+ //! <b>Effects</b>: Swaps two trees. After the function header1 will contain \r
+ //! links to the second tree and header2 will have links to the first tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void swap_tree(node_ptr header1, node_ptr header2)\r
+ {\r
+ if(header1 == header2)\r
+ return;\r
+ \r
+ node_ptr tmp;\r
+\r
+ //Parent swap\r
+ tmp = NodeTraits::get_parent(header1);\r
+ NodeTraits::set_parent(header1, NodeTraits::get_parent(header2));\r
+ NodeTraits::set_parent(header2, tmp);\r
+ //Left swap\r
+ tmp = NodeTraits::get_left(header1);\r
+ NodeTraits::set_left(header1, NodeTraits::get_left(header2));\r
+ NodeTraits::set_left(header2, tmp);\r
+ //Right swap\r
+ tmp = NodeTraits::get_right(header1);\r
+ NodeTraits::set_right(header1, NodeTraits::get_right(header2));\r
+ NodeTraits::set_right(header2, tmp);\r
+\r
+ //Now test parent\r
+ node_ptr h1_parent(NodeTraits::get_parent(header1));\r
+ if(h1_parent){\r
+ NodeTraits::set_parent(h1_parent, header1);\r
+ }\r
+ else{\r
+ NodeTraits::set_left(header1, header1);\r
+ NodeTraits::set_right(header1, header1);\r
+ }\r
+\r
+ node_ptr h2_parent(NodeTraits::get_parent(header2));\r
+ if(NodeTraits::get_parent(header2)){\r
+ NodeTraits::set_parent(h2_parent, header2);\r
+ }\r
+ else{\r
+ NodeTraits::set_left(header2, header2);\r
+ NodeTraits::set_right(header2, header2);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: node is a tree node but not the header.\r
+ //! \r
+ //! <b>Effects</b>: Unlinks the node and rebalances the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void unlink_and_rebalance(node_ptr node)\r
+ {\r
+ if(NodeTraits::get_parent(node)){\r
+ node_ptr x = NodeTraits::get_parent(node);\r
+ while(!is_header(x))\r
+ x = NodeTraits::get_parent(x);\r
+ erase(x, node);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: header is the header of a tree.\r
+ //! \r
+ //! <b>Effects</b>: Unlinks the leftmost node from the tree, and\r
+ //! updates the header link to the new leftmost node.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Notes</b>: This function breaks the tree and the tree can\r
+ //! only be used for more unlink_leftmost_without_rebalance calls.\r
+ //! This function is normally used to achieve a step by step\r
+ //! controlled destruction of the tree.\r
+ static node_ptr unlink_leftmost_without_rebalance(node_ptr header)\r
+ {\r
+ node_ptr leftmost = NodeTraits::get_left(header);\r
+ if (leftmost == header)\r
+ return 0;\r
+ node_ptr leftmost_parent(NodeTraits::get_parent(leftmost));\r
+ node_ptr leftmost_right (NodeTraits::get_right(leftmost));\r
+ bool is_root = leftmost_parent == header;\r
+\r
+ if (leftmost_right){\r
+ NodeTraits::set_parent(leftmost_right, leftmost_parent);\r
+ NodeTraits::set_left(header, minimum(leftmost_right));\r
+\r
+ if (is_root)\r
+ NodeTraits::set_parent(header, leftmost_right);\r
+ else\r
+ NodeTraits::set_left(NodeTraits::get_parent(header), leftmost_right);\r
+ }\r
+ else if (is_root){\r
+ NodeTraits::set_parent(header, 0);\r
+ NodeTraits::set_left(header, header);\r
+ NodeTraits::set_right(header, header);\r
+ }\r
+ else{\r
+ NodeTraits::set_left(leftmost_parent, 0);\r
+ NodeTraits::set_left(header, leftmost_parent);\r
+ }\r
+ return leftmost;\r
+ }\r
+\r
+ //! <b>Requires</b>: node is a node of the tree or an node initialized\r
+ //! by init(...).\r
+ //! \r
+ //! <b>Effects</b>: Returns true if the node is initialized by init().\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static bool unique(const_node_ptr node)\r
+ { return NodeTraits::get_parent(node) == 0; }\r
+\r
+ //! <b>Requires</b>: node is a node of the tree but it's not the header.\r
+ //! \r
+ //! <b>Effects</b>: Returns the number of nodes of the subtree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static std::size_t count(const_node_ptr node)\r
+ {\r
+ std::size_t result = 1;\r
+ if(NodeTraits::get_left(node))\r
+ result += count(NodeTraits::get_left(node));\r
+ if(NodeTraits::get_right(node))\r
+ result += count(NodeTraits::get_right(node));\r
+ return result;\r
+ }\r
+\r
+ //! <b>Requires</b>: p is a node from the tree except the header.\r
+ //! \r
+ //! <b>Effects</b>: Returns the next node of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Average constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr next_node(node_ptr p)\r
+ {\r
+ node_ptr p_right(NodeTraits::get_right(p));\r
+ if(p_right){\r
+ return minimum(p_right);\r
+ }\r
+ else {\r
+ node_ptr x = NodeTraits::get_parent(p);\r
+ while(p == NodeTraits::get_right(x)){\r
+ p = x;\r
+ x = NodeTraits::get_parent(x);\r
+ }\r
+ return NodeTraits::get_right(p) != x ? x : uncast(p);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: p is a node from the tree except the leftmost node.\r
+ //! \r
+ //! <b>Effects</b>: Returns the previous node of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Average constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr prev_node(node_ptr p)\r
+ {\r
+ if(is_header(p)){\r
+ return NodeTraits::get_right(p); // p is header, return rightmost\r
+ }\r
+ else if(NodeTraits::get_left(p)){\r
+ return maximum(NodeTraits::get_left(p));\r
+ }\r
+ else {\r
+ node_ptr x = NodeTraits::get_parent(p);\r
+ while(p == NodeTraits::get_left(x)){\r
+ p = x;\r
+ x = NodeTraits::get_parent(x);\r
+ }\r
+ return x;\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: node must not be part of any tree.\r
+ //!\r
+ //! <b>Effects</b>: After the function unique(node) == true.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //!\r
+ //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.\r
+ static void init(node_ptr node)\r
+ {\r
+ NodeTraits::set_parent(node, 0);\r
+ NodeTraits::set_left(node, 0);\r
+ NodeTraits::set_right(node, 0); \r
+ NodeTraits::set_color(node, NodeTraits::black());\r
+ };\r
+\r
+ //! <b>Requires</b>: node must not be part of any tree.\r
+ //!\r
+ //! <b>Effects</b>: Initializes the header to represent an empty tree.\r
+ //! unique(header) == true.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //!\r
+ //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.\r
+ static void init_header(node_ptr header)\r
+ {\r
+ NodeTraits::set_parent(header, 0);\r
+ NodeTraits::set_left(header, header);\r
+ NodeTraits::set_right(header, header); \r
+ NodeTraits::set_color(header, NodeTraits::red()); \r
+ };\r
+\r
+ //! <b>Requires</b>: header must be the header of a tree, z a node\r
+ //! of that tree and z != header.\r
+ //!\r
+ //! <b>Effects</b>: Erases node "z" from the tree with header "header".\r
+ //! \r
+ //! <b>Complexity</b>: Amortized constant time.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr erase(node_ptr header, node_ptr z)\r
+ {\r
+ node_ptr y(z);\r
+ node_ptr x(0);\r
+ node_ptr x_parent(0);\r
+ node_ptr y_left(NodeTraits::get_left(y));\r
+ node_ptr y_right(NodeTraits::get_right(y));\r
+ if(!y_left){\r
+ x = y_right; // x might be null.\r
+ }\r
+ else if(!y_right){ // z has exactly one non-null child. y == z.\r
+ x = y_left; // x is not null.\r
+ }\r
+ else{\r
+ y = minimum (y_right);\r
+ x = NodeTraits::get_right(y); // x might be null.\r
+ }\r
+\r
+ if(y != z){\r
+ // relink y in place of z. y is z's successor\r
+ NodeTraits::set_parent(NodeTraits::get_left(z), y);\r
+ NodeTraits::set_left(y, NodeTraits::get_left(z));\r
+ if(y != NodeTraits::get_right(z)){\r
+ x_parent = NodeTraits::get_parent(y);\r
+ if(x)\r
+ NodeTraits::set_parent(x, NodeTraits::get_parent(y));\r
+ NodeTraits::set_left(NodeTraits::get_parent(y), x); // y must be a child of left_\r
+ NodeTraits::set_right(y, NodeTraits::get_right(z));\r
+ NodeTraits::set_parent(NodeTraits::get_right(z), y);\r
+ }\r
+ else\r
+ x_parent = y;\r
+ replace_own (z, y, header);\r
+ NodeTraits::set_parent(y, NodeTraits::get_parent(z));\r
+ color tmp(NodeTraits::get_color(y));\r
+ tmp = NodeTraits::get_color(y);\r
+ NodeTraits::set_color(y, NodeTraits::get_color(z));\r
+ NodeTraits::set_color(z, tmp);\r
+// std::swap(NodeTraits::get_color(y), NodeTraits::get_color(z));\r
+ y = z;\r
+ // y now points to node to be actually deleted\r
+ }\r
+ else { // y == z\r
+ x_parent = NodeTraits::get_parent(y);\r
+ if(x)\r
+ NodeTraits::set_parent(x, NodeTraits::get_parent(y));\r
+ replace_own (z, x, header);\r
+ if(NodeTraits::get_left(header) == z){\r
+ NodeTraits::set_left(header, NodeTraits::get_right(z) == 0 ? // z->get_left() must be null also\r
+ NodeTraits::get_parent(z) : // makes leftmost == header if z == root\r
+ minimum (x));\r
+ }\r
+ if(NodeTraits::get_right(header) == z){\r
+ NodeTraits::set_right(header, NodeTraits::get_left(z) == 0 ? // z->get_right() must be null also\r
+ NodeTraits::get_parent(z) : // makes rightmost == header if z == root\r
+ maximum(x));\r
+ }\r
+ }\r
+ if(NodeTraits::get_color(y) != NodeTraits::red()){\r
+ while(x != NodeTraits::get_parent(header) && (x == 0 || NodeTraits::get_color(x) == NodeTraits::black())){\r
+ if(x == NodeTraits::get_left(x_parent)){\r
+ node_ptr w = NodeTraits::get_right(x_parent);\r
+ if(NodeTraits::get_color(w) == NodeTraits::red()){\r
+ NodeTraits::set_color(w, NodeTraits::black());\r
+ NodeTraits::set_color(x_parent, NodeTraits::red());\r
+ rotate_left(x_parent, header);\r
+ w = NodeTraits::get_right(x_parent);\r
+ }\r
+ if((NodeTraits::get_left(w) == 0 || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black()) &&\r
+ (NodeTraits::get_right(w) == 0 || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black())){\r
+ NodeTraits::set_color(w, NodeTraits::red());\r
+ x = x_parent;\r
+ x_parent = NodeTraits::get_parent(x_parent);\r
+ } \r
+ else {\r
+ if(NodeTraits::get_right(w) == 0 || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black()){\r
+ NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black());\r
+ NodeTraits::set_color(w, NodeTraits::red());\r
+ rotate_right(w, header);\r
+ w = NodeTraits::get_right(x_parent);\r
+ }\r
+ NodeTraits::set_color(w, NodeTraits::get_color(x_parent));\r
+ NodeTraits::set_color(x_parent, NodeTraits::black());\r
+ if(NodeTraits::get_right(w))\r
+ NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black());\r
+ rotate_left(x_parent, header);\r
+ break;\r
+ }\r
+ }\r
+ else {\r
+ // same as above, with right_ <-> left_.\r
+ node_ptr w = NodeTraits::get_left(x_parent);\r
+ if(NodeTraits::get_color(w) == NodeTraits::red()){\r
+ NodeTraits::set_color(w, NodeTraits::black());\r
+ NodeTraits::set_color(x_parent, NodeTraits::red());\r
+ rotate_right(x_parent, header);\r
+ w = NodeTraits::get_left(x_parent);\r
+ }\r
+ if((NodeTraits::get_right(w) == 0 || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black()) &&\r
+ (NodeTraits::get_left(w) == 0 || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black())){\r
+ NodeTraits::set_color(w, NodeTraits::red());\r
+ x = x_parent;\r
+ x_parent = NodeTraits::get_parent(x_parent);\r
+ }\r
+ else {\r
+ if(NodeTraits::get_left(w) == 0 || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black()){\r
+ NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black());\r
+ NodeTraits::set_color(w, NodeTraits::red());\r
+ rotate_left(w, header);\r
+ w = NodeTraits::get_left(x_parent);\r
+ }\r
+ NodeTraits::set_color(w, NodeTraits::get_color(x_parent));\r
+ NodeTraits::set_color(x_parent, NodeTraits::black());\r
+ if(NodeTraits::get_left(w))\r
+ NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black());\r
+ rotate_right(x_parent, header);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if(x)\r
+ NodeTraits::set_color(x, NodeTraits::black());\r
+ }\r
+ return y;\r
+ }\r
+\r
+ //! <b>Requires</b>: "cloner" must be a function\r
+ //! object taking a node_ptr and returning a new cloned node of it. "destroyer" must\r
+ //! take a node_ptr and shouldn't throw.\r
+ //!\r
+ //! <b>Effects</b>: First empties target tree calling \r
+ //! <tt>void destroyer::operator()(node_ptr)</tt> for every node of the tree\r
+ //! except the header.\r
+ //! \r
+ //! Then, duplicates the entire tree pointed by "source_header" cloning each\r
+ //! source node with <tt>node_ptr Cloner::operator()(node_ptr)</tt> to obtain \r
+ //! the nodes of the target tree. If "cloner" throws, the cloned target nodes\r
+ //! are destroyed using <tt>void destroyer(node_ptr)</tt>.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of element of the source tree plus the.\r
+ //! number of elements of tree target tree when calling this function.\r
+ //! \r
+ //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are destroyed.\r
+ template <class Cloner, class Destroyer>\r
+ static void clone_tree\r
+ (const_node_ptr source_header, node_ptr target_header, Cloner cloner, Destroyer destroyer)\r
+ {\r
+ if(!unique(target_header)){\r
+ node_ptr p;\r
+ while((p = unlink_leftmost_without_rebalance(target_header))){\r
+ destroyer(p);\r
+ }\r
+ }\r
+\r
+ node_ptr source_root = NodeTraits::get_parent(source_header);\r
+ if(!source_root)\r
+ return;\r
+\r
+ NodeTraits::set_parent\r
+ ( target_header\r
+ , deep_clone_node(source_root, target_header, cloner, destroyer));\r
+ NodeTraits::set_left(target_header, minimum(NodeTraits::get_parent(target_header)));\r
+ NodeTraits::set_right(target_header, maximum(NodeTraits::get_parent(target_header)));\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! KeyNodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.\r
+ //!\r
+ //! <b>Effects</b>: Returns an node_ptr to the first element that is\r
+ //! not less than "key" according to "comp" or "header" if that element does\r
+ //! not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class KeyType, class KeyNodePtrCompare>\r
+ static node_ptr lower_bound\r
+ (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp)\r
+ {\r
+ node_ptr y = uncast(header);\r
+ node_ptr x = NodeTraits::get_parent(header);\r
+ while(x){\r
+ if(comp(x, key)){\r
+ x = NodeTraits::get_right(x);\r
+ }\r
+ else {\r
+ y = x;\r
+ x = NodeTraits::get_left(x);\r
+ }\r
+ }\r
+ return y;\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! KeyNodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.\r
+ //!\r
+ //! <b>Effects</b>: Returns an node_ptr to the first element that is greater\r
+ //! than "key" according to "comp" or "header" if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class KeyType, class KeyNodePtrCompare>\r
+ static node_ptr upper_bound\r
+ (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp)\r
+ {\r
+ node_ptr y = uncast(header);\r
+ node_ptr x = NodeTraits::get_parent(header);\r
+ while(x){\r
+ if(comp(key, x)){\r
+ y = x;\r
+ x = NodeTraits::get_left(x);\r
+ }\r
+ else {\r
+ x = NodeTraits::get_right(x);\r
+ }\r
+ }\r
+ return y;\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! KeyNodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.\r
+ //!\r
+ //! <b>Effects</b>: Returns an node_ptr to the element that is equivalent to\r
+ //! "key" according to "comp" or "header" if that element does not exist.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class KeyType, class KeyNodePtrCompare>\r
+ static node_ptr find\r
+ (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp)\r
+ {\r
+ node_ptr end = uncast(header);\r
+ node_ptr y = lower_bound(header, key, comp);\r
+ return (y == end || comp(key, y)) ? end : y;\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! KeyNodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.\r
+ //!\r
+ //! <b>Effects</b>: Returns an a pair of node_ptr delimiting a range containing\r
+ //! all elements that are equivalent to "key" according to "comp" or an\r
+ //! empty range that indicates the position where those elements would be\r
+ //! if they there are no equivalent elements.\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class KeyType, class KeyNodePtrCompare>\r
+ static std::pair<node_ptr, node_ptr> equal_range\r
+ (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp)\r
+ {\r
+ node_ptr y = uncast(header);\r
+ node_ptr x = NodeTraits::get_parent(header);\r
+\r
+ while(x){\r
+ if(comp(x, key)){\r
+ x = NodeTraits::get_right(x);\r
+ }\r
+ else if(comp(key, x)){\r
+ y = x;\r
+ x = NodeTraits::get_left(x);\r
+ }\r
+ else{\r
+ node_ptr xu(x), yu(y);\r
+ y = x, x = NodeTraits::get_left(x);\r
+ xu = NodeTraits::get_right(xu);\r
+\r
+ while(x){\r
+ if(comp(x, key)){\r
+ x = NodeTraits::get_right(x);\r
+ }\r
+ else {\r
+ y = x;\r
+ x = NodeTraits::get_left(x);\r
+ }\r
+ }\r
+\r
+ while(xu){\r
+ if(comp(key, xu)){\r
+ yu = xu;\r
+ xu = NodeTraits::get_left(xu);\r
+ }\r
+ else {\r
+ xu = NodeTraits::get_right(xu);\r
+ }\r
+ }\r
+ return std::pair<node_ptr,node_ptr>(y, yu);\r
+ }\r
+ }\r
+ return std::pair<node_ptr,node_ptr>(y, y);\r
+ }\r
+\r
+ //! <b>Requires</b>: "h" must be the header node of a tree.\r
+ //! NodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. NodePtrCompare compares two node_ptrs.\r
+ //!\r
+ //! <b>Effects</b>: Inserts new_node into the tree before the upper bound\r
+ //! according to "comp".\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class NodePtrCompare>\r
+ static node_ptr insert_equal_upper_bound\r
+ (node_ptr h, node_ptr new_node, NodePtrCompare comp)\r
+ {\r
+ node_ptr y(h);\r
+ node_ptr x(NodeTraits::get_parent(y));\r
+\r
+ while(x){\r
+ y = x;\r
+ x = comp(new_node, x) ? \r
+ NodeTraits::get_left(x) : NodeTraits::get_right(x);\r
+ }\r
+\r
+ bool link_left = (y == h) || \r
+ comp(new_node, y);\r
+ link_and_balance(new_node, y, link_left, h);\r
+ return new_node;\r
+ }\r
+\r
+ //! <b>Requires</b>: "h" must be the header node of a tree.\r
+ //! NodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. NodePtrCompare compares two node_ptrs.\r
+ //!\r
+ //! <b>Effects</b>: Inserts new_node into the tree before the lower bound\r
+ //! according to "comp".\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity for insert element is at\r
+ //! most logarithmic.\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class NodePtrCompare>\r
+ static node_ptr insert_equal_lower_bound\r
+ (node_ptr h, node_ptr new_node, NodePtrCompare comp)\r
+ {\r
+ node_ptr y(h);\r
+ node_ptr x(NodeTraits::get_parent(y));\r
+\r
+ while(x){\r
+ y = x;\r
+ x = !comp(x, new_node) ? \r
+ NodeTraits::get_left(x) : NodeTraits::get_right(x);\r
+ }\r
+\r
+ bool link_left = (y == h) || \r
+ !comp(y, new_node);\r
+ link_and_balance(new_node, y, link_left, h);\r
+ return new_node;\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! NodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from\r
+ //! the "header"'s tree.\r
+ //! \r
+ //! <b>Effects</b>: Inserts new_node into the tree, using "hint" as a hint to\r
+ //! where it will be inserted. If "hint" is the upper_bound\r
+ //! the insertion takes constant time (two comparisons in the worst case).\r
+ //!\r
+ //! <b>Complexity</b>: Logarithmic in general, but it is amortized\r
+ //! constant time if new_node is inserted immediately before "hint".\r
+ //! \r
+ //! <b>Throws</b>: If "comp" throws.\r
+ template<class NodePtrCompare>\r
+ static node_ptr insert_equal\r
+ (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp)\r
+ {\r
+ if(hint == header || !comp(hint, new_node)){\r
+ node_ptr prev(hint);\r
+ if(hint == NodeTraits::get_left(header) || \r
+ !comp(new_node, (prev = prev_node(hint)))){\r
+ bool link_left = unique(header) || !NodeTraits::get_left(hint);\r
+ link_and_balance(new_node, link_left ? hint : prev, link_left, header);\r
+ return new_node;\r
+ }\r
+ else{\r
+ return insert_equal_upper_bound(header, new_node, comp);\r
+ }\r
+ }\r
+ else{\r
+ return insert_equal_lower_bound(header, new_node, comp);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! KeyNodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. NodePtrCompare compares KeyType with a node_ptr.\r
+ //! \r
+ //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the\r
+ //! tree according to "comp" and obtains the needed information to realize\r
+ //! a constant-time node insertion if there is no equivalent node.\r
+ //!\r
+ //! <b>Returns</b>: If an equivalent node is already present\r
+ //! returns a pair containing a node_ptr to the already present node\r
+ //! and false. If there is not equivalent key can be inserted returns true\r
+ //! in the returned pair's boolean and fills "commit_data" that is meant to\r
+ //! be used with the "insert_commit" function to achieve a constant-time\r
+ //! insertion function.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is at most logarithmic.\r
+ //!\r
+ //! <b>Throws</b>: If "comp" throws.\r
+ //! \r
+ //! <b>Notes</b>: This function is used to improve performance when constructing\r
+ //! a node is expensive and the user does not want to have two equivalent nodes\r
+ //! in the tree: if an equivalent node is already present\r
+ //! the constructed object must be discarded. Many times, the part of the\r
+ //! node that is used to impose the order is much cheaper to construct\r
+ //! than the node and this function offers the possibility to use that part\r
+ //! to check if the insertion will be successful.\r
+ //!\r
+ //! If the check is successful, the user can construct the node and use\r
+ //! "insert_commit" to insert the node in constant-time. This gives a total\r
+ //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).\r
+ //!\r
+ //! "commit_data" remains valid for a subsequent "insert_unique_commit" only\r
+ //! if no more objects are inserted or erased from the set.\r
+ template<class KeyType, class KeyNodePtrCompare>\r
+ static std::pair<node_ptr, bool> insert_unique_check\r
+ (const_node_ptr header, const KeyType &key\r
+ ,KeyNodePtrCompare comp, insert_commit_data &commit_data)\r
+ {\r
+ node_ptr h(uncast(header));\r
+ node_ptr y(h);\r
+ node_ptr x(NodeTraits::get_parent(y));\r
+ node_ptr prev(0);\r
+\r
+ //Find the upper bound, cache the previous value and if we should\r
+ //store it in the left or right node\r
+ bool left_child = true;\r
+ while(x){\r
+ y = x;\r
+ x = (left_child = comp(key, x)) ? \r
+ NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x));\r
+ }\r
+\r
+ //Since we've found the upper bound there is no other value with the same key if:\r
+ // - There is no previous node\r
+ // - The previous node is less than the key\r
+ if(!prev || comp(prev, key)){\r
+ commit_data.link_left = left_child;\r
+ commit_data.node = y;\r
+ return std::pair<node_ptr, bool>(node_ptr(), true);\r
+ }\r
+ //If the previous value was not less than key, it means that it's equal\r
+ //(because we've checked the upper bound)\r
+ else{\r
+ return std::pair<node_ptr, bool>(prev, false);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! KeyNodePtrCompare is a function object that induces a strict weak\r
+ //! ordering compatible with the strict weak ordering used to create the\r
+ //! the tree. NodePtrCompare compares KeyType with a node_ptr.\r
+ //! "hint" is node from the "header"'s tree.\r
+ //! \r
+ //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the\r
+ //! tree according to "comp" using "hint" as a hint to where it should be\r
+ //! inserted and obtains the needed information to realize\r
+ //! a constant-time node insertion if there is no equivalent node. \r
+ //! If "hint" is the upper_bound the function has constant time \r
+ //! complexity (two comparisons in the worst case).\r
+ //!\r
+ //! <b>Returns</b>: If an equivalent node is already present\r
+ //! returns a pair containing a node_ptr to the already present node\r
+ //! and false. If there is not equivalent key can be inserted returns true\r
+ //! in the returned pair's boolean and fills "commit_data" that is meant to\r
+ //! be used with the "insert_commit" function to achieve a constant-time\r
+ //! insertion function.\r
+ //! \r
+ //! <b>Complexity</b>: Average complexity is at most logarithmic, but it is\r
+ //! amortized constant time if new_node should be inserted immediately before "hint".\r
+ //!\r
+ //! <b>Throws</b>: If "comp" throws.\r
+ //! \r
+ //! <b>Notes</b>: This function is used to improve performance when constructing\r
+ //! a node is expensive and the user does not want to have two equivalent nodes\r
+ //! in the tree: if an equivalent node is already present\r
+ //! the constructed object must be discarded. Many times, the part of the\r
+ //! node that is used to impose the order is much cheaper to construct\r
+ //! than the node and this function offers the possibility to use that part\r
+ //! to check if the insertion will be successful.\r
+ //!\r
+ //! If the check is successful, the user can construct the node and use\r
+ //! "insert_commit" to insert the node in constant-time. This gives a total\r
+ //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).\r
+ //!\r
+ //! "commit_data" remains valid for a subsequent "insert_unique_commit" only\r
+ //! if no more objects are inserted or erased from the set.\r
+ template<class KeyType, class KeyNodePtrCompare>\r
+ static std::pair<node_ptr, bool> insert_unique_check\r
+ (const_node_ptr header, node_ptr hint, const KeyType &key\r
+ ,KeyNodePtrCompare comp, insert_commit_data &commit_data)\r
+ {\r
+ //hint must be bigger than the key\r
+ if(hint == header || comp(key, hint)){\r
+ node_ptr prev = hint;\r
+ //The previous value should be less than the key\r
+ if(prev == NodeTraits::get_left(header) || comp((prev = prev_node(hint)), key)){\r
+ commit_data.link_left = unique(header) || !NodeTraits::get_left(hint);\r
+ commit_data.node = commit_data.link_left ? hint : prev;\r
+ return std::pair<node_ptr, bool>(node_ptr(), true);\r
+ }\r
+ else{\r
+ return insert_unique_check(header, key, comp, commit_data);\r
+ //return std::pair<node_ptr, bool>(prev, false);\r
+ }\r
+ }\r
+ //The hint was wrong, use hintless insert\r
+ else{\r
+ return insert_unique_check(header, key, comp, commit_data);\r
+ }\r
+ }\r
+\r
+ //! <b>Requires</b>: "header" must be the header node of a tree.\r
+ //! "commit_data" must have been obtained from a previous call to\r
+ //! "insert_unique_check". No objects should have been inserted or erased\r
+ //! from the set between the "insert_unique_check" that filled "commit_data"\r
+ //! and the call to "insert_commit". \r
+ //! \r
+ //! \r
+ //! <b>Effects</b>: Inserts new_node in the set using the information obtained\r
+ //! from the "commit_data" that a previous "insert_check" filled.\r
+ //!\r
+ //! <b>Complexity</b>: Constant time.\r
+ //!\r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Notes</b>: This function has only sense if a "insert_unique_check" has been\r
+ //! previously executed to fill "commit_data". No value should be inserted or\r
+ //! erased between the "insert_check" and "insert_commit" calls.\r
+ static void insert_unique_commit\r
+ (node_ptr header, node_ptr new_value, const insert_commit_data &commit_data)\r
+ {\r
+ //Check if commit_data has not been initialized by a insert_unique_check call.\r
+ BOOST_ASSERT(commit_data.node != 0);\r
+ link_and_balance(new_value, commit_data.node, commit_data.link_left, header);\r
+ }\r
+\r
+ private:\r
+\r
+ static node_ptr uncast(const_node_ptr ptr)\r
+ {\r
+ using boost::get_pointer;\r
+ return node_ptr(const_cast<node*>(get_pointer(ptr)));\r
+ }\r
+\r
+ //! <b>Requires</b>: z is the node to be inserted, par is its parent,\r
+ //! left, indicates if z should be a left node of par and header is the header\r
+ //! of the tree.\r
+ //! \r
+ //! <b>Effects</b>: If left is true links z as a left child of par or as a right\r
+ //! child otherwise. After that rebalances the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Average constant time.???\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void link_and_balance (node_ptr z, node_ptr par, bool left, node_ptr header)\r
+ {\r
+ if(par == header){\r
+ NodeTraits::set_parent(header, z);\r
+ NodeTraits::set_right(header, z);\r
+ NodeTraits::set_left(header, z);\r
+ }\r
+ else if(left){\r
+ NodeTraits::set_left(par, z);\r
+ if(par == NodeTraits::get_left(header))\r
+ NodeTraits::set_left(header, z);\r
+ }\r
+ else{\r
+ NodeTraits::set_right(par, z);\r
+ if(par == NodeTraits::get_right(header))\r
+ NodeTraits::set_right(header, z);\r
+ }\r
+ NodeTraits::set_parent(z, par);\r
+ NodeTraits::set_right(z, 0);\r
+ NodeTraits::set_left(z, 0);\r
+ rebalance(z, header);\r
+ }\r
+\r
+ //! <b>Requires</b>: p is a node of a tree but not the header.\r
+ //! \r
+ //! <b>Effects</b>: Returns the minimum node of the subtree starting at p.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the size of the subtree.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr minimum (node_ptr p)\r
+ {\r
+ for(node_ptr p_left = NodeTraits::get_left(p)\r
+ ;p_left\r
+ ;p_left = NodeTraits::get_left(p)){\r
+ p = p_left;\r
+ }\r
+ return p;\r
+ }\r
+\r
+ //! <b>Requires</b>: p is a node of a tree but not the header.\r
+ //! \r
+ //! <b>Effects</b>: Returns the maximum node of the subtree starting at p.\r
+ //! \r
+ //! <b>Complexity</b>: Logarithmic to the size of the subtree.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr maximum(node_ptr p)\r
+ {\r
+ for(node_ptr p_right = NodeTraits::get_right(p)\r
+ ;p_right\r
+ ;p_right = NodeTraits::get_right(p)){\r
+ p = p_right;\r
+ }\r
+ return p;\r
+ }\r
+\r
+ //! <b>Requires</b>: p is a node of a tree.\r
+ //! \r
+ //! <b>Effects</b>: Returns true if p is the header of the tree.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static bool is_header(const_node_ptr p)\r
+ {\r
+ return NodeTraits::get_color(p) == NodeTraits::red() && \r
+ NodeTraits::get_parent(NodeTraits::get_parent(p)) == p;\r
+ }\r
+\r
+ //! <b>Requires</b>: p is a node of a tree.\r
+ //! \r
+ //! <b>Effects</b>: Returns true if p is a left child.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static bool is_left_child(node_ptr p)\r
+ { return NodeTraits::get_left(NodeTraits::get_parent(p)) == p; }\r
+\r
+ //! <b>Requires</b>: p is a node of a tree.\r
+ //! \r
+ //! <b>Effects</b>: Returns true if p is a right child.\r
+ //! \r
+ //! <b>Complexity</b>: Constant.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static bool is_right_child (node_ptr p)\r
+ { return NodeTraits::get_right(NodeTraits::get_parent(p)) == p; }\r
+\r
+ static void replace_own (node_ptr own, node_ptr x, node_ptr header)\r
+ {\r
+ if(NodeTraits::get_parent(header) == own)\r
+ NodeTraits::set_parent(header, x);\r
+ else if(is_left_child(own))\r
+ NodeTraits::set_left(NodeTraits::get_parent(own), x);\r
+ else\r
+ NodeTraits::set_right(NodeTraits::get_parent(own), x);\r
+ }\r
+\r
+ static void rotate_left(node_ptr p, node_ptr header)\r
+ {\r
+ node_ptr x = NodeTraits::get_right(p);\r
+ NodeTraits::set_right(p, NodeTraits::get_left(x));\r
+ if(NodeTraits::get_left(x) != 0)\r
+ NodeTraits::set_parent(NodeTraits::get_left(x), p);\r
+ NodeTraits::set_parent(x, NodeTraits::get_parent(p));\r
+ replace_own (p, x, header);\r
+ NodeTraits::set_left(x, p);\r
+ NodeTraits::set_parent(p, x);\r
+ }\r
+\r
+ static void rotate_right(node_ptr p, node_ptr header)\r
+ {\r
+ node_ptr x(NodeTraits::get_left(p));\r
+ node_ptr x_right(NodeTraits::get_right(x));\r
+ NodeTraits::set_left(p, x_right);\r
+ if(x_right)\r
+ NodeTraits::set_parent(x_right, p);\r
+ NodeTraits::set_parent(x, NodeTraits::get_parent(p));\r
+ replace_own (p, x, header);\r
+ NodeTraits::set_right(x, p);\r
+ NodeTraits::set_parent(p, x);\r
+ }\r
+\r
+ static void rebalance(node_ptr p, node_ptr header)\r
+ {\r
+ NodeTraits::set_color(p, NodeTraits::red());\r
+ while(p != NodeTraits::get_parent(header) && NodeTraits::get_color(NodeTraits::get_parent(p)) == NodeTraits::red()){\r
+ node_ptr p_parent(NodeTraits::get_parent(p));\r
+ node_ptr p_parent_parent(NodeTraits::get_parent(p_parent));\r
+ if(is_left_child(p_parent)){\r
+ node_ptr x = NodeTraits::get_right(p_parent_parent);\r
+ if(x && NodeTraits::get_color(x) == NodeTraits::red()){\r
+ NodeTraits::set_color(p_parent, NodeTraits::black());\r
+ NodeTraits::set_color(p_parent_parent, NodeTraits::red());\r
+ NodeTraits::set_color(x, NodeTraits::black());\r
+ p = p_parent_parent;\r
+ }\r
+ else {\r
+ if(!is_left_child(p)){\r
+ p = p_parent;\r
+ rotate_left(p, header);\r
+ }\r
+ node_ptr new_p_parent(NodeTraits::get_parent(p));\r
+ node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent));\r
+ NodeTraits::set_color(new_p_parent, NodeTraits::black());\r
+ NodeTraits::set_color(new_p_parent_parent, NodeTraits::red());\r
+ rotate_right(new_p_parent_parent, header);\r
+ }\r
+ }\r
+ else{\r
+ node_ptr x = NodeTraits::get_left(p_parent_parent);\r
+ if(x && NodeTraits::get_color(x) == NodeTraits::red()){\r
+ NodeTraits::set_color(p_parent, NodeTraits::black());\r
+ NodeTraits::set_color(p_parent_parent, NodeTraits::red());\r
+ NodeTraits::set_color(x, NodeTraits::black());\r
+ p = p_parent_parent;\r
+ }\r
+ else{\r
+ if(is_left_child(p)){\r
+ p = p_parent;\r
+ rotate_right(p, header);\r
+ }\r
+ node_ptr new_p_parent(NodeTraits::get_parent(p));\r
+ node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent));\r
+ NodeTraits::set_color(new_p_parent, NodeTraits::black());\r
+ NodeTraits::set_color(new_p_parent_parent, NodeTraits::red());\r
+ rotate_left(new_p_parent_parent, header);\r
+ }\r
+ }\r
+ }\r
+ NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black());\r
+ }\r
+\r
+ template <class Cloner, class Destroyer>\r
+ static node_ptr deep_clone_node\r
+ (node_ptr source_root, node_ptr new_parent, Cloner cloner, Destroyer destroyer)\r
+ {\r
+ // structural copy. source_root and new_parent must be non-null.\r
+ node_ptr top = cloner(source_root);\r
+ NodeTraits::set_parent(top, new_parent);\r
+ \r
+ BOOST_TRY {\r
+ if(NodeTraits::get_right(source_root)){\r
+ NodeTraits::set_right\r
+ (top, deep_clone_node(NodeTraits::get_right(source_root), top\r
+ ,cloner, destroyer));\r
+ }\r
+ new_parent = top;\r
+ source_root = NodeTraits::get_left(source_root);\r
+\r
+ while(source_root){\r
+ node_ptr y = cloner(source_root);\r
+ NodeTraits::set_left(new_parent, y);\r
+ NodeTraits::set_parent(y, new_parent);\r
+\r
+ if(NodeTraits::get_right(source_root)){\r
+ NodeTraits::set_right(y, deep_clone_node(NodeTraits::get_right(source_root), y\r
+ ,cloner, destroyer));\r
+ }\r
+ new_parent = y;\r
+ source_root = NodeTraits::get_left(source_root);\r
+ }\r
+ }\r
+ BOOST_CATCH(...){\r
+ deep_destroy_node(top, destroyer);\r
+ BOOST_RETHROW;\r
+ }\r
+ BOOST_CATCH_END\r
+ return top;\r
+ }\r
+\r
+ template<class Destroyer>\r
+ static void deep_destroy_node(node_ptr x, Destroyer destroyer)\r
+ {\r
+ // erase without rebalancing\r
+ while(x){\r
+ deep_destroy_node(NodeTraits::get_right(x), destroyer);\r
+ node_ptr y = NodeTraits::get_left(x);\r
+ destroyer(x);\r
+ x = y;\r
+ }\r
+ }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP\r
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Olaf Krzikalla 2004-2006.\r
+// (C) Copyright Ion GaztaƱaga 2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+// (See accompanying file LICENSE_1_0.txt or copy at\r
+// http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef BOOST_INTRUSIVE_SLIST_ALGORITHMS_HPP\r
+#define BOOST_INTRUSIVE_SLIST_ALGORITHMS_HPP\r
+\r
+#include <boost/intrusive/detail/config_begin.hpp>\r
+#include <iterator>\r
+#include <boost/assert.hpp>\r
+#include <boost/intrusive/detail/pointer_type.hpp>\r
+#include <boost/intrusive/detail/pointer_to_other.hpp>\r
+#include <boost/get_pointer.hpp>\r
+#include <cstddef>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+\r
+//! slist_algorithms provides basic algorithms to manipulate nodes\r
+//! forming a circular singly linked list. An empty circular list is formed by a node\r
+//! whose pointer to the next node points to itself.\r
+//!\r
+//! slist_algorithms is configured with a NodeTraits class, which capsulates the\r
+//! information about the node to be manipulated. NodeTraits must support the\r
+//! following interface:\r
+//!\r
+//! <b>Typedefs</b>:\r
+//!\r
+//! <tt>node</tt>: The type of the node that forms the circular list\r
+//!\r
+//! <tt>node_ptr</tt>: A pointer to a node\r
+//!\r
+//! <tt>const_node_ptr</tt>: A pointer to a const node\r
+//!\r
+//! <b>Static functions</b>:\r
+//!\r
+//! <tt>static node_ptr get_next(const_node_ptr n);</tt>\r
+//! \r
+//! <tt>static void set_next(node_ptr n, node_ptr next);</tt>\r
+template<class NodeTraits>\r
+class slist_algorithms\r
+{\r
+ public:\r
+ typedef typename NodeTraits::node_ptr node_ptr;\r
+ typedef typename NodeTraits::const_node_ptr const_node_ptr;\r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Returns the previous node of this_node in the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the circular list.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr get_previous_node(node_ptr this_node)\r
+ {\r
+ node_ptr p = this_node;\r
+ while (this_node != NodeTraits::get_next(p))\r
+ p = NodeTraits::get_next(p);\r
+ return p;\r
+ }\r
+\r
+ //! <b>Requires</b>: this_node and prev_init_node must be in the same circular list.\r
+ //! \r
+ //! <b>Effects</b>: Returns the previous node of this_node in the circular list starting.\r
+ //! the search from prev_init_node. The first node checked for equality\r
+ //! is NodeTraits::get_next(prev_init_node).\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements between prev_init_node and this_node.\r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static node_ptr get_previous_node(node_ptr prev_init_node, node_ptr this_node)\r
+ {\r
+ node_ptr p = prev_init_node;\r
+ while (this_node != NodeTraits::get_next(p))\r
+ p = NodeTraits::get_next(p);\r
+ return p;\r
+ }\r
+\r
+ //! <b>Effects</b>: Constructs an empty list, making this_node the only\r
+ //! node of the circular list:\r
+ //! <tt>NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node)\r
+ //! == this_node</tt>.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void init(node_ptr this_node) \r
+ { NodeTraits::set_next(this_node, this_node); } \r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:\r
+ //! <tt>return NodeTraits::get_next(this_node) == this_node</tt>\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static bool unique(const_node_ptr this_node) \r
+ { return NodeTraits::get_next(this_node) == this_node; }\r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list\r
+ //! is empty, returns 1.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static std::size_t count(const_node_ptr this_node) \r
+ {\r
+ std::size_t result = 0;\r
+ const_node_ptr p = this_node;\r
+ do{\r
+ p = NodeTraits::get_next(p);\r
+ ++result;\r
+ } while (p != this_node);\r
+ return result;\r
+ }\r
+\r
+ //! <b>Requires</b>: prev_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Unlinks the next node of prev_node from the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void unlink_after(node_ptr prev_node)\r
+ {\r
+ node_ptr this_node(NodeTraits::get_next(prev_node));\r
+ NodeTraits::set_next(prev_node, NodeTraits::get_next(this_node));\r
+ NodeTraits::set_next(this_node, this_node);\r
+ }\r
+\r
+ //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.\r
+ //! \r
+ //! <b>Effects</b>: Unlinks the node from the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the circular list \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void unlink(node_ptr this_node)\r
+ { unlink_after(get_previous_node(this_node)); }\r
+\r
+ //! <b>Requires</b>: prev_node must be a node of a circular list.\r
+ //! \r
+ //! <b>Effects</b>: Links this_node after prev_node in the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void link_after(node_ptr prev_node, node_ptr this_node)\r
+ {\r
+ NodeTraits::set_next(this_node, NodeTraits::get_next(prev_node));\r
+ NodeTraits::set_next(prev_node, this_node);\r
+ }\r
+\r
+ //! <b>Requires</b>: nxt_node must be a node of a circular list.\r
+ //! \r
+ //! <b>Effects</b>: Links this_node before nxt_node in the circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to the number of elements in the circular list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void link_before (node_ptr nxt_node, node_ptr this_node)\r
+ { link_after(get_previous_node(nxt_node), this_node); }\r
+\r
+ //! <b>Requires</b>: this_node and other_node must be nodes inserted\r
+ //! in circular lists or be empty circular lists.\r
+ //! \r
+ //! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in\r
+ //! other_nodes position in the second circular list and the other_node is inserted\r
+ //! in this_node's position in the first circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Linear to number of elements of both lists \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void swap_nodes(node_ptr this_node, node_ptr other_node)\r
+ {\r
+ if (other_node == this_node)\r
+ return;\r
+ bool empty1 = unique(this_node);\r
+ bool empty2 = unique(other_node);\r
+ node_ptr prev_this (get_previous_node(this_node));\r
+ node_ptr prev_other(get_previous_node(other_node));\r
+\r
+ node_ptr this_next (NodeTraits::get_next(this_node));\r
+ node_ptr other_next(NodeTraits::get_next(other_node));\r
+ NodeTraits::set_next(this_node, other_next);\r
+ NodeTraits::set_next(other_node, this_next);\r
+ NodeTraits::set_next(empty1 ? other_node : prev_this, other_node);\r
+ NodeTraits::set_next(empty2 ? this_node : prev_other, this_node);\r
+ }\r
+\r
+ //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.\r
+ //! and p must be a node of a different circular list.\r
+ //! \r
+ //! <b>Effects</b>: Removes the nodes from [b, e) range from their circular list and inserts\r
+ //! them after p in p's circular list.\r
+ //! \r
+ //! <b>Complexity</b>: Constant \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ static void transfer_after(node_ptr p, node_ptr b, node_ptr e)\r
+ {\r
+ if (p != b && p != e) {\r
+ node_ptr next_b = NodeTraits::get_next(b);\r
+ node_ptr next_e = NodeTraits::get_next(e);\r
+ node_ptr next_p = NodeTraits::get_next(p);\r
+ NodeTraits::set_next(b, next_e);\r
+ NodeTraits::set_next(e, next_p);\r
+ NodeTraits::set_next(p, next_b);\r
+ }\r
+ }\r
+\r
+ //! <b>Effects</b>: Reverses the order of elements in the list. \r
+ //! \r
+ //! <b>Throws</b>: Nothing.\r
+ //! \r
+ //! <b>Complexity</b>: This function is linear to the contained elements.\r
+ static void reverse(node_ptr p)\r
+ {\r
+ node_ptr i = NodeTraits::get_next(p), e(p); \r
+ for (;;) {\r
+ node_ptr nxt(NodeTraits::get_next(i));\r
+ if (nxt == e)\r
+ break;\r
+ transfer_after(e, i, nxt);\r
+ }\r
+ }\r
+};\r
+\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include <boost/intrusive/detail/config_end.hpp>\r
+\r
+#endif //BOOST_INTRUSIVE_SLIST_ALGORITHMS_HPP\r
--- /dev/null
+#!/bin/sh
+
+find . \
+ -name .svn -prune -o \
+ -name doc -prune -o \
+ -name "*.a" -o \
+ -name "*.o" -o \
+ -name "*~" -o \
+ -name "#*#" -o \
+ -name "*.pyc" -o \
+ -name .test.bin -o \
+ -name "*.stamp" -o \
+ -name ".sconsign*" -o \
+ -type f \( "$@" \)
+