V
Virchanza
I'm currently writing a program that deals with containers which
contain containers which contain containers.
I'm simplifying things here a bit, but what I have is something like:
class Port_Data {};
class IP_Data {
vector<Port_Data> ports;
};
class MAC_Data {
vector<IP_Data> ips;
};
class SnifferDatabase {
vector<MAC_Data> macs;
};
SnifferDatabase *const g_sdb = new SnifferDatabase();
The program works but it's way too slow. What's slowing things down is
the vector class's use of "malloc/new" to allocate memory (this can be
improved slightly by calling reserve() on the vectors beforehand).
Now I don't know if I'm inventing the wheel here or not, but I've put
something together that fixes my performance problem.
Basically, I've created an Adapter class that lets you use a normal
array just as if it were a vector (it cuts out the dynamic memory
allocation). I get the feeling this has been done before??? My code
now looks like:
class Port_Data {};
class IP_Data {
SuperArray<Port_Data,255> ports;
};
class MAC_Data {
SuperArray<IP_Data,255> ips;
};
class SnifferDatabase {
SuperArray<MAC_Data,255> macs;
};
SnifferDatabase *const g_sdb = new SnifferDatabase();
Now, as you can see, there's only one case of dynamic memory
allocation (i.e. when the g_sdb variable gets initialised).
My particular Adapter class is different from an std::vector in a few
ways:
* It can't be copy-constructed or assigned to (this is purely for my
own needs in my own program).
* The "push_back" method can take an argument of any type (again, this
is for my own program).
Anyway here's my code for SuperArray:
#include <cstddef>
template< typename T, std::size_t len >
class SuperArray {
private:
/* ------ Prevent copy-construction and assignment------ */
SuperArray(SuperArray const &);
SuperArray &operator=(SuperArray const &);
/* ----------------------------------------------------- */
char unsigned raw_mem[ sizeof( T[len] ) ];
T *const pbegin;
T *pend;
T const *const pend_of_allocated_space;
public:
/* ---------- First here comes the types ---------- */
typedef std::size_t size_type;
typedef T value_type;
typedef T &reference;
typedef T const &const_reference;
typedef T *iterator, *pointer;
typedef T const *const_iterator, *const_pointer;
/* ------------------------------------------------ */
SuperArray()
: pbegin( static_cast<T*>( static_cast<void*>(raw_mem) ) ),
pend( pbegin ),
pend_of_allocated_space( pbegin + len )
{
/* Nothing */
}
bool empty() const { return pend == pbegin; }
size_type capacity() const { return len; }
size_type max_size() const { return len; }
size_type size() const { return pend - pbegin; }
reference operator[](size_t const i) { return pbegin; }
const_reference operator[](size_t const i) const { return
pbegin; }
iterator begin() { return pbegin; }
const_iterator begin() const { return pbegin; }
iterator end() { return pend; }
const_iterator end() const { return pend; }
reference front() { return *pbegin; }
const_reference front() const { return *pbegin; }
reference back() { return pend[-1]; }
const_reference back() const { return pend[-1]; }
template<class X>
void push_back(X const &val)
{
if ( pend_of_allocated_space == pend )
{
/* Wups we're full! */
throw -1;
}
/* Let the following throw if it wants to */
::new(pend) T(val);
++pend; /* This doesn't happens if the placement new throws
*/
}
void pop_back()
{
back().~T();
--pend;
}
void clear()
{
while ( !empty() )
pop_back();
}
};
Of course I could add stuff to it like rbegin() and rend() but I don't
need that stuff in my program right now.
contain containers which contain containers.
I'm simplifying things here a bit, but what I have is something like:
class Port_Data {};
class IP_Data {
vector<Port_Data> ports;
};
class MAC_Data {
vector<IP_Data> ips;
};
class SnifferDatabase {
vector<MAC_Data> macs;
};
SnifferDatabase *const g_sdb = new SnifferDatabase();
The program works but it's way too slow. What's slowing things down is
the vector class's use of "malloc/new" to allocate memory (this can be
improved slightly by calling reserve() on the vectors beforehand).
Now I don't know if I'm inventing the wheel here or not, but I've put
something together that fixes my performance problem.
Basically, I've created an Adapter class that lets you use a normal
array just as if it were a vector (it cuts out the dynamic memory
allocation). I get the feeling this has been done before??? My code
now looks like:
class Port_Data {};
class IP_Data {
SuperArray<Port_Data,255> ports;
};
class MAC_Data {
SuperArray<IP_Data,255> ips;
};
class SnifferDatabase {
SuperArray<MAC_Data,255> macs;
};
SnifferDatabase *const g_sdb = new SnifferDatabase();
Now, as you can see, there's only one case of dynamic memory
allocation (i.e. when the g_sdb variable gets initialised).
My particular Adapter class is different from an std::vector in a few
ways:
* It can't be copy-constructed or assigned to (this is purely for my
own needs in my own program).
* The "push_back" method can take an argument of any type (again, this
is for my own program).
Anyway here's my code for SuperArray:
#include <cstddef>
template< typename T, std::size_t len >
class SuperArray {
private:
/* ------ Prevent copy-construction and assignment------ */
SuperArray(SuperArray const &);
SuperArray &operator=(SuperArray const &);
/* ----------------------------------------------------- */
char unsigned raw_mem[ sizeof( T[len] ) ];
T *const pbegin;
T *pend;
T const *const pend_of_allocated_space;
public:
/* ---------- First here comes the types ---------- */
typedef std::size_t size_type;
typedef T value_type;
typedef T &reference;
typedef T const &const_reference;
typedef T *iterator, *pointer;
typedef T const *const_iterator, *const_pointer;
/* ------------------------------------------------ */
SuperArray()
: pbegin( static_cast<T*>( static_cast<void*>(raw_mem) ) ),
pend( pbegin ),
pend_of_allocated_space( pbegin + len )
{
/* Nothing */
}
bool empty() const { return pend == pbegin; }
size_type capacity() const { return len; }
size_type max_size() const { return len; }
size_type size() const { return pend - pbegin; }
reference operator[](size_t const i) { return pbegin; }
const_reference operator[](size_t const i) const { return
pbegin; }
iterator begin() { return pbegin; }
const_iterator begin() const { return pbegin; }
iterator end() { return pend; }
const_iterator end() const { return pend; }
reference front() { return *pbegin; }
const_reference front() const { return *pbegin; }
reference back() { return pend[-1]; }
const_reference back() const { return pend[-1]; }
template<class X>
void push_back(X const &val)
{
if ( pend_of_allocated_space == pend )
{
/* Wups we're full! */
throw -1;
}
/* Let the following throw if it wants to */
::new(pend) T(val);
++pend; /* This doesn't happens if the placement new throws
*/
}
void pop_back()
{
back().~T();
--pend;
}
void clear()
{
while ( !empty() )
pop_back();
}
};
Of course I could add stuff to it like rbegin() and rend() but I don't
need that stuff in my program right now.