#include <memory>
#include <map>
#include <stdexcept>
using namespace std;
class NoSuchNode:public runtime_error
{
public:
NoSuchNode(const char* str):runtime_error(str){}
NoSuchNode():runtime_error("can not find th node"){}
};
class NodeHasExist:public runtime_error
{
public:
NodeHasExist():runtime_error("the node has existed"){}
};
template <typename T>
struct Edge
{
T weight;
};
template <typename X,typename Y>
class AdMatrix
{
int num;
map<int,unique_ptr<Y>> nodes;
unique_ptr<unique_ptr<Edge<X>[]>[]> edges;
bool isNode(int no);
public:
AdMatrix(int num);
void addEdge(int from,int to, const X & weight);
void addEdge(int from,int to, X && weight);
int addNode(int no);
Edge<X>& getEdge(int from,int to);
Y& getNode(int no);
};
template <typename X,typename Y>
Y& AdMatrix<X,Y>::getNode(int no)
{
if(this->isNode(no))
return *this->nodes[no];
else
throw NoSuchNode();
}
template <typename X,typename Y>
Edge<X>& AdMatrix<X,Y>::getEdge(int from,int to)
{
if(this->isNode(from) && this->isNode(to))
return this->edges[from][to];
else
throw NoSuchNode();
}
template <typename X,typename Y>
AdMatrix<X,Y>::AdMatrix(int num)
{
this->edges = unique_ptr<unique_ptr<Edge<X>[]>[]>(new unique_ptr<Edge<X>[]>[num]);
for (int i=0; i<num; i++) {
this->edges[i] = unique_ptr<Edge<X>[]>(new Edge<X>[num]);
}
this->num = num;
}
template <typename X,typename Y>
bool AdMatrix<X,Y>::isNode(int no)
{
auto it = this->nodes.find(no);
if(it!=this->nodes.end())
return true;
else
return false;
}
template <typename X,typename Y>
int AdMatrix<X,Y>::addNode(int no)
{
if(this->isNode(no))
throw NodeHasExist();
else
this->nodes[no]=unique_ptr<Y>(new Y());
return no;
}
template <typename X,typename Y>
void AdMatrix<X,Y>::addEdge(int from, int to, const X & weight)
{
if(this->isNode(from) && this->isNode(to))
this->edges[from][to].weight=weight;
else
throw NoSuchNode();
}
template <typename X,typename Y>
void AdMatrix<X,Y>::addEdge(int from, int to,X && weight)
{
if(this->isNode(from) && this->isNode(to))
this->edges[from][to].weight=move(weight);
else
throw NoSuchNode();
}
----main
#include "AdMatrix.h"
#include <vector>
class EdgeWeight
{
int character_t;
bool isEmpty_t;
public:
EdgeWeight(){this->isEmpty_t=true;this->character_t=-1;}
EdgeWeight(int character)
{
this->character_t = character;
this->isEmpty_t=false;
}
bool isChar(int character);
void setEmpty(bool isEmpty){this->isEmpty_t = isEmpty;}
bool isEmpty(){return this->isEmpty_t;}
};
struct Node
{
bool isVisited;
vector<int> edges_to; //even other container,set
Node(){this->isVisited=false;}
};
int main(int args,char** argvs)
{
AdMatrix<unique_ptr<EdgeWeight>,Node> matrix(5);
matrix.addNode(1);
matrix.addNode(2);
matrix.addEdge(1, 2, unique_ptr<EdgeWeight>(new EdgeWeight(10)));
auto & node = matrix.getNode(1);
node.edges_to.push_back(1);
return 0;
}
someone who ran it on Linux has not find any error. Even checked with Valgrind, and did not find any memory issues.
My develop environment:
Mac OS X 10.10.2
dialect c++11
libc++
Xcode Version 6.3.2 (6D2105)
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
The error:(I can not upload the image)
libc++abi.dylib: terminating with uncaught exception of type std::length_error: vector
Related
I'm looking into a solution of building containers which track stored size of their elements in addition to basic functions.
So far I didn't saw a solution which doesn't create a huge amount of boilerplate code of each invalidating member of container. This also assumes that stored elements cannot change size after being stored.
Unless standard containers have some feature that allows to inject such behaviour. The following example should be working one, albeit abridged for brevity. The declarations used are:
typedef uint8_t Byte;
typedef Byte PacketId;
template <class T>
struct CollectionTraits {
typedef T collection_type;
typedef typename collection_type::value_type value_type;
typedef typename collection_type::size_type size_type;
typedef typename collection_type::iterator iterator;
typedef typename collection_type::reference reference;
typedef typename collection_type::const_iterator const_iterator;
const_iterator begin() const { return _collection.begin(); }
const_iterator end() const { return _collection.end(); }
iterator begin() { return _collection.begin(); }
iterator end() { return _collection.end(); }
size_type size() const { return _collection.size(); }
protected:
T _collection;
};
struct Packet : CollectionTraits<std::vector<Byte>>
{
PacketId id;
};
The container itself:
struct PacketList : CollectionTraits<std::deque<Packet>>
{
public:
typedef Packet::size_type data_size;
void clear() { _collection.clear(); _total_size = 0; }
data_size total_size() const { return _total_size; }
void push_back(const Packet& v) {
_collection.push_back(v);
_add(v);
}
void push_back(const Packet&& v) {
_collection.push_back(std::move(v));
_add(v);
}
void push_front(const Packet& v) {
_collection.push_front(v);
_add(v);
}
void push_front(const Packet&& v) {
_collection.push_front(std::move(v));
_add(v);
}
void pop_back() {
_remove(_collection.back());
_collection.pop_back();
}
void erase(const_iterator first, const_iterator last) {
for(auto it = first; it != last; ++it) _remove(*it);
_collection.erase(first, last);
}
PacketList() : _total_size(0) {}
PacketList(const PacketList& other) : _total_size(other._total_size) {}
private:
void _add(const Packet& v) { _total_size += v.size(); }
void _remove(const Packet& v) { _total_size -= v.size(); }
data_size _total_size;
};
The interface in result should similar to a standard container. Is there a way to avoid this amount of repeated code? Is there some standard solution for this problem?
My code runs ok when thread number is 15 or less, but when I run it with larger thread number (but still a very tiny number) say 50. I ran into following error when main function exits, seems like error occurs in the cleaning up process. I couldn't figure out where the bug is. My development tool is Visual Studio 2017. Here's my code:
threadsafe_queue class:
#pragma once
#include <memory>
#include <mutex>
template<typename T>
class threadsafe_queue
{
private:
struct Node {
std::shared_ptr<T> data;
std::unique_ptr<Node> next;
};
Node* tail;
std::unique_ptr<Node> head;
std::mutex head_mutex;
std::mutex tail_mutex;
std::condition_variable data_cond;
Node* get_tail();
std::unique_ptr<Node> pop_head();
std::unique_lock<std::mutex> wait_for_data();
public:
threadsafe_queue();
~threadsafe_queue();
threadsafe_queue(const threadsafe_queue& t) = delete;
threadsafe_queue operator = (const threadsafe_queue& t) = delete;
void push(T);
bool try_pop(T&);
std::shared_ptr<T> try_pop();
void wait_and_pop(T&);
std::shared_ptr<T> wait_and_pop();
bool empty();
};
using namespace std;
template<typename T>
threadsafe_queue<T>::threadsafe_queue() {
head = std::unique_ptr<Node>(new Node);
tail = head.get();
}
template<typename T>
threadsafe_queue<T>::~threadsafe_queue()
{
}
template<typename T>
typename threadsafe_queue<T>::Node* threadsafe_queue<T>::get_tail() {
lock_guard<mutex> lock(tail_mutex);
return tail;
}
template<typename T>
unique_ptr<typename threadsafe_queue<T>::Node> threadsafe_queue<T>::pop_head()
{
auto old_head = move(head);
head = move(old_head->next);
return old_head;
}
template<typename T>
unique_lock<mutex> threadsafe_queue<T>::wait_for_data()
{
unique_lock<mutex> headLock(head_mutex);
data_cond.wait(headLock, [&] {return head.get() != get_tail(); });
return std::move(headLock);
}
template<typename T>
void threadsafe_queue<T>::wait_and_pop(T & value)
{
unique_lock<mutex> lock(wait_for_data());
value = move(pop_head()->data);
}
template<typename T>
shared_ptr<T> threadsafe_queue<T>::wait_and_pop()
{
unique_lock<mutex> lock(wait_for_data());
return pop_head()->data;
}
template<typename T>
void threadsafe_queue<T>::push(T newValue)
{
shared_ptr<T> data(make_shared<T>(std::move(newValue)));
unique_ptr<Node> new_tail(new Node);
{
lock_guard<mutex> lock(tail_mutex);
tail->data = data;
Node* new_tail_ptr = new_tail.get();
tail->next = move(new_tail);
tail = new_tail_ptr;
}
data_cond.notify_one();
}
template<typename T>
bool threadsafe_queue<T>::try_pop(T & value)
{
lock_guard<mutex> headLock(head_mutex);
if (head == get_tail())
return false;
value = move(pop_head()->data);
return true;
}
template<typename T>
shared_ptr<T> threadsafe_queue<T>::try_pop()
{
lock_guard<mutex> headLock(head_mutex);
if (head == get_tail())
return shared_ptr<T>();
return pop_head()->data;
}
template<typename T>
bool threadsafe_queue<T>::empty()
{
lock_guard<mutex> lock(head_mutex);
return head.get() == get_tail();
}
main function:
#pragma once
#include "threadsafe_queue.h"
#include <assert.h>
#include <memory>
#include <atomic>
#include <vector>
#include <thread>
using namespace std;
void worker(threadsafe_queue<int>& queue, std::atomic<int>& count, int const & pushcount, int const & popcount) {
for (unsigned i = 0; i < pushcount; i++) {
queue.push(i);
count++;
}
for (unsigned i = 0; i < popcount; i++) {
queue.wait_and_pop();
count--;
}
}
int main() {
threadsafe_queue<int> queue;
std::atomic<int> item_count = 0;
std::vector<thread*> threads;
unsigned const THREAD_COUNT=50, PUSH_COUT=100, POP_COUNT=50;
for (unsigned i = 0; i < THREAD_COUNT; i++) {
threads.push_back(new thread(worker, ref(queue), ref(item_count), ref(PUSH_COUT), ref(POP_COUNT)));
}
for (auto thread : threads) {
thread->join();
}
for (auto thread : threads) {
delete thread;
}
assert(item_count == THREAD_COUNT * (PUSH_COUT-POP_COUNT));
return 0;
}
error message:
Unhandled exception at 0x00862899 in Sample.exe: 0xC00000FD: Stack overflow
(parameters: 0x00000001, 0x00E02FDC). occurred
The location of the error is in memory library code:
const pointer& _Myptr() const _NOEXCEPT
{ // return const reference to pointer
return (_Mypair._Get_second());
}
The answer is based on #IgorTandetnik 's comment above. Basically I needed to implement ~threadsafe_queue to destroy the nodes iteratively. The nodes are linked, so they will be destructed in recursive manner, which causes stack overflow when number of nodes remaining in the queue is relatively large. Below is the destructor code.
threadsafe_queue<T>::~threadsafe_queue(){
Node* current = head.release();
while (current != tail) {
Node* temp = (current->next).release();
delete current;
current = temp;
}
delete tail;
}
I'm using omnet5, veins 4.4, and sumo 0.25. I've looked at Converting Veins Coordinates to GPS which didn't help much since i have the updated version.
This one https://stackoverflow.com/questions/40650825/connection-to-traci-server-lost-check-your-servers-log-error-message-88-soc seems like it might work with a little error checking, but I'm not sure what the user did to make it work.
I've seen that you can use omnet2traci to convert the regular coordinates to the sumo ones, but I'm having trouble implementing it properly. When I tried calling it in message with:
class Veins::TraCIConnection::omnet2traci;
then using:
Veins::TraCICoord gpspos = omnet2traci(senderPos);
but I'm getting undeclared identifier error. I tried changing to .cc and .h code to compensate for it by creating a small copy of the omnet2traci coding from TraCIConnection. After all that it gives me errors:
omnetpp-5.0/include/omnetpp/cdynamicexpression.h:50:9: error: expected identifier
ADD, SUB, MUL, DIV, MOD, POW, NEG,
^
.\veins/modules/mobility/traci/TraCIConstants.h:707:13: note: expanded from macro 'ADD'
#define ADD 0x80
^
omnetpp-5.0/include/omnetpp/coutvector.h:66:27: error: expected identifier
enum Type { TYPE_INT, TYPE_DOUBLE, TYPE_ENUM };
^
.\veins/modules/mobility/traci/TraCIConstants.h:304:21: note: expanded from macro 'TYPE_DOUBLE'
#define TYPE_DOUBLE 0x0B
^
At this point it seems like it working around the problem and hoping it works instead of actually solving the problem. Full code below, added in parts are starred. *note I had to snip the end parts of the .cc code because it went over the text limit, but nothing was changed.
Waveshortmessage.msg
//Waveshortmessage.msg
cplusplus {{
**#include <stdint.h>
#include "veins/modules/mobility/traci/TraCIBuffer.h"
#include "veins/modules/mobility/traci/TraCICommandInterface.h"
#include "veins/modules/mobility/traci/TraCIConnection.h"
#include "veins/modules/mobility/traci/TraCIConstants.h"
#include "veins/modules/mobility/traci/TraCICoord.h"**
#include "veins/base/utils/Coord.h"
}}
class noncobject Coord;
**class noncobject Veins::TraCICoord;
class Veins::TraCIConnection::omnet2traci;**
packet WaveShortMessage {
//Version of the Wave Short Message
int wsmVersion = 0;
//Determine which security mechanism was used
int securityType = 0;
//Channel Number on which this packet was sent
int channelNumber;
//Data rate with which this packet was sent
int dataRate = 1;
//Power Level with which this packet was sent
int priority = 3;
//Unique number to identify the service
int psid = 0;
//Provider Service Context
string psc = "Service with some Data";
//Length of Wave Short Message
int wsmLength;
//Data of Wave Short Message
string wsmData = "Some Data";
int senderAddress = 0;
int recipientAddress = -1;
int serial = 0;
Coord senderPos;
**Veins::TraCICoord gpspos = omnet2traci(senderPos);**
simtime_t timestamp = 0;
}
Waveshortmessage.cc
//waveshortmessage.cc
// Generated file, do not edit! Created by nedtool 5.0 from veins/modules/messages/WaveShortMessage.msg.
//
**#define WANT_WINSOCK2
#include <platdep/sockets.h>
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) || defined(_WIN64)
#include <ws2tcpip.h>
#else
#include <netinet/tcp.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include <algorithm>
#include <functional>
//#include "veins/modules/mobility/traci/TraCIConnection.h"
#include "veins/modules/mobility/traci/TraCIConstants.h"
#define MYDEBUG EV**
// Disable warnings about unused variables, empty switch stmts, etc:
#ifdef _MSC_VER
# pragma warning(disable:4101)
# pragma warning(disable:4065)
#endif
#include <iostream>
#include <sstream>
#include "WaveShortMessage_m.h"
namespace omnetpp {
// Template pack/unpack rules. They are declared *after* a1l type-specific pack functions for multiple reasons.
// They are in the omnetpp namespace, to allow them to be found by argument-dependent lookup via the cCommBuffer argument
// Packing/unpacking an std::vector
template<typename T, typename A>
void doParsimPacking(omnetpp::cCommBuffer *buffer, const std::vector<T,A>& v)
{
int n = v.size();
doParsimPacking(buffer, n);
for (int i = 0; i < n; i++)
doParsimPacking(buffer, v[i]);
}
template<typename T, typename A>
void doParsimUnpacking(omnetpp::cCommBuffer *buffer, std::vector<T,A>& v)
{
int n;
doParsimUnpacking(buffer, n);
v.resize(n);
for (int i = 0; i < n; i++)
doParsimUnpacking(buffer, v[i]);
}
// Packing/unpacking an std::list
template<typename T, typename A>
void doParsimPacking(omnetpp::cCommBuffer *buffer, const std::list<T,A>& l)
{
doParsimPacking(buffer, (int)l.size());
for (typename std::list<T,A>::const_iterator it = l.begin(); it != l.end(); ++it)
doParsimPacking(buffer, (T&)*it);
}
template<typename T, typename A>
void doParsimUnpacking(omnetpp::cCommBuffer *buffer, std::list<T,A>& l)
{
int n;
doParsimUnpacking(buffer, n);
for (int i=0; i<n; i++) {
l.push_back(T());
doParsimUnpacking(buffer, l.back());
}
}
// Packing/unpacking an std::set
template<typename T, typename Tr, typename A>
void doParsimPacking(omnetpp::cCommBuffer *buffer, const std::set<T,Tr,A>& s)
{
doParsimPacking(buffer, (int)s.size());
for (typename std::set<T,Tr,A>::const_iterator it = s.begin(); it != s.end(); ++it)
doParsimPacking(buffer, *it);
}
template<typename T, typename Tr, typename A>
void doParsimUnpacking(omnetpp::cCommBuffer *buffer, std::set<T,Tr,A>& s)
{
int n;
doParsimUnpacking(buffer, n);
for (int i=0; i<n; i++) {
T x;
doParsimUnpacking(buffer, x);
s.insert(x);
}
}
// Packing/unpacking an std::map
template<typename K, typename V, typename Tr, typename A>
void doParsimPacking(omnetpp::cCommBuffer *buffer, const std::map<K,V,Tr,A>& m)
{
doParsimPacking(buffer, (int)m.size());
for (typename std::map<K,V,Tr,A>::const_iterator it = m.begin(); it != m.end(); ++it) {
doParsimPacking(buffer, it->first);
doParsimPacking(buffer, it->second);
}
}
template<typename K, typename V, typename Tr, typename A>
void doParsimUnpacking(omnetpp::cCommBuffer *buffer, std::map<K,V,Tr,A>& m)
{
int n;
doParsimUnpacking(buffer, n);
for (int i=0; i<n; i++) {
K k; V v;
doParsimUnpacking(buffer, k);
doParsimUnpacking(buffer, v);
m[k] = v;
}
}
// Default pack/unpack function for arrays
template<typename T>
void doParsimArrayPacking(omnetpp::cCommBuffer *b, const T *t, int n)
{
for (int i = 0; i < n; i++)
doParsimPacking(b, t[i]);
}
template<typename T>
void doParsimArrayUnpacking(omnetpp::cCommBuffer *b, T *t, int n)
{
for (int i = 0; i < n; i++)
doParsimUnpacking(b, t[i]);
}
// Default rule to prevent compiler from choosing base class' doParsimPacking() function
template<typename T>
void doParsimPacking(omnetpp::cCommBuffer *, const T& t)
{
throw omnetpp::cRuntimeError("Parsim error: no doParsimPacking() function for type %s", omnetpp::opp_typename(typeid(t)));
}
template<typename T>
void doParsimUnpacking(omnetpp::cCommBuffer *, T& t)
{
throw omnetpp::cRuntimeError("Parsim error: no doParsimUnpacking() function for type %s", omnetpp::opp_typename(typeid(t)));
}
} // namespace omnetpp
// forward
template<typename T, typename A>
std::ostream& operator<<(std::ostream& out, const std::vector<T,A>& vec);
// Template rule which fires if a struct or class doesn't have operator<<
template<typename T>
inline std::ostream& operator<<(std::ostream& out,const T&) {return out;}
// operator<< for std::vector<T>
template<typename T, typename A>
inline std::ostream& operator<<(std::ostream& out, const std::vector<T,A>& vec)
{
out.put('{');
for(typename std::vector<T,A>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
if (it != vec.begin()) {
out.put(','); out.put(' ');
}
out << *it;
}
out.put('}');
char buf[32];
sprintf(buf, " (size=%u)", (unsigned int)vec.size());
out.write(buf, strlen(buf));
return out;
}
**Veins::TraCICoord Veins::TraCIConnection::omnet2traci(Coord coord) const {
return TraCICoord(coord.x + netbounds1.x - margin, (netbounds2.y - netbounds1.y) - (coord.y - netbounds1.y) + margin);
}
std::list<Veins::TraCICoord> Veins::TraCIConnection::omnet2traci(const std::list<Coord>& list) const {
std::list<TraCICoord> result;
std::transform(list.begin(), list.end(), std::back_inserter(result), std::bind1st(std::mem_fun<TraCICoord, TraCIConnection, Coord>(&TraCIConnection::omnet2traci), this));
return result;
}**
Register_Class(WaveShortMessage);
WaveShortMessage::WaveShortMessage(const char *name, int kind) : ::omnetpp::cPacket(name,kind)
{
this->wsmVersion = 0;
this->securityType = 0;
this->channelNumber = 0;
this->dataRate = 1;
this->priority = 3;
this->psid = 0;
this->psc = "Service with some Data";
this->wsmLength = 0;
this->wsmData = "Some Data";
this->senderAddress = 0;
this->recipientAddress = -1;
this->serial = 0;
this->gpspos = omnet2traci(senderPos);
this->timestamp = 0;
}
WaveShortMessage::WaveShortMessage(const WaveShortMessage& other) : ::omnetpp::cPacket(other)
{
copy(other);
}
WaveShortMessage::~WaveShortMessage()
{
}
WaveShortMessage& WaveShortMessage::operator=(const WaveShortMessage& other)
{
if (this==&other) return *this;
::omnetpp::cPacket::operator=(other);
copy(other);
return *this;
}
void WaveShortMessage::copy(const WaveShortMessage& other)
{
this->wsmVersion = other.wsmVersion;
this->securityType = other.securityType;
this->channelNumber = other.channelNumber;
this->dataRate = other.dataRate;
this->priority = other.priority;
this->psid = other.psid;
this->psc = other.psc;
this->wsmLength = other.wsmLength;
this->wsmData = other.wsmData;
this->senderAddress = other.senderAddress;
this->recipientAddress = other.recipientAddress;
this->serial = other.serial;
this->senderPos = other.senderPos;
this->gpspos = other.gpspos;
this->timestamp = other.timestamp;
}
void WaveShortMessage::parsimPack(omnetpp::cCommBuffer *b) const
{
::omnetpp::cPacket::parsimPack(b);
doParsimPacking(b,this->wsmVersion);
doParsimPacking(b,this->securityType);
doParsimPacking(b,this->channelNumber);
doParsimPacking(b,this->dataRate);
doParsimPacking(b,this->priority);
doParsimPacking(b,this->psid);
doParsimPacking(b,this->psc);
doParsimPacking(b,this->wsmLength);
doParsimPacking(b,this->wsmData);
doParsimPacking(b,this->senderAddress);
doParsimPacking(b,this->recipientAddress);
doParsimPacking(b,this->serial);
doParsimPacking(b,this->senderPos);
doParsimPacking(b,this->gpspos);
doParsimPacking(b,this->timestamp);
}
void WaveShortMessage::parsimUnpack(omnetpp::cCommBuffer *b)
{
::omnetpp::cPacket::parsimUnpack(b);
doParsimUnpacking(b,this->wsmVersion);
doParsimUnpacking(b,this->securityType);
doParsimUnpacking(b,this->channelNumber);
doParsimUnpacking(b,this->dataRate);
doParsimUnpacking(b,this->priority);
doParsimUnpacking(b,this->psid);
doParsimUnpacking(b,this->psc);
doParsimUnpacking(b,this->wsmLength);
doParsimUnpacking(b,this->wsmData);
doParsimUnpacking(b,this->senderAddress);
doParsimUnpacking(b,this->recipientAddress);
doParsimUnpacking(b,this->serial);
doParsimUnpacking(b,this->senderPos);
doParsimUnpacking(b,this->gpspos);
doParsimUnpacking(b,this->timestamp);
}
int WaveShortMessage::getWsmVersion() const
{
return this->wsmVersion;
}
void WaveShortMessage::setWsmVersion(int wsmVersion)
{
this->wsmVersion = wsmVersion;
}
int WaveShortMessage::getSecurityType() const
{
return this->securityType;
}
void WaveShortMessage::setSecurityType(int securityType)
{
this->securityType = securityType;
}
int WaveShortMessage::getChannelNumber() const
{
return this->channelNumber;
}
void WaveShortMessage::setChannelNumber(int channelNumber)
{
this->channelNumber = channelNumber;
}
int WaveShortMessage::getDataRate() const
{
return this->dataRate;
}
void WaveShortMessage::setDataRate(int dataRate)
{
this->dataRate = dataRate;
}
int WaveShortMessage::getPriority() const
{
return this->priority;
}
void WaveShortMessage::setPriority(int priority)
{
this->priority = priority;
}
int WaveShortMessage::getPsid() const
{
return this->psid;
}
void WaveShortMessage::setPsid(int psid)
{
this->psid = psid;
}
const char * WaveShortMessage::getPsc() const
{
return this->psc.c_str();
}
void WaveShortMessage::setPsc(const char * psc)
{
this->psc = psc;
}
int WaveShortMessage::getWsmLength() const
{
return this->wsmLength;
}
void WaveShortMessage::setWsmLength(int wsmLength)
{
this->wsmLength = wsmLength;
}
const char * WaveShortMessage::getWsmData() const
{
return this->wsmData.c_str();
}
void WaveShortMessage::setWsmData(const char * wsmData)
{
this->wsmData = wsmData;
}
int WaveShortMessage::getSenderAddress() const
{
return this->senderAddress;
}
void WaveShortMessage::setSenderAddress(int senderAddress)
{
this->senderAddress = senderAddress;
}
int WaveShortMessage::getRecipientAddress() const
{
return this->recipientAddress;
}
void WaveShortMessage::setRecipientAddress(int recipientAddress)
{
this->recipientAddress = recipientAddress;
}
int WaveShortMessage::getSerial() const
{
return this->serial;
}
void WaveShortMessage::setSerial(int serial)
{
this->serial = serial;
}
Coord& WaveShortMessage::getSenderPos()
{
return this->senderPos;
}
void WaveShortMessage::setSenderPos(const Coord& senderPos)
{
this->senderPos = senderPos;
}
Veins::TraCICoord& WaveShortMessage::getGpspos()
{
return this->gpspos;
}
void WaveShortMessage::setGpspos(const Veins::TraCICoord& gpspos)
{
this->gpspos = gpspos;
}
::omnetpp::simtime_t WaveShortMessage::getTimestamp() const
{
return this->timestamp;
}
void WaveShortMessage::setTimestamp(::omnetpp::simtime_t timestamp)
{
this->timestamp = timestamp;
}
class WaveShortMessageDescriptor : public omnetpp::cClassDescriptor
{
private:
mutable const char **propertynames;
public:
WaveShortMessageDescriptor();
virtual ~WaveShortMessageDescriptor();
virtual bool doesSupport(omnetpp::cObject *obj) const override;
virtual const char **getPropertyNames() const override;
virtual const char *getProperty(const char *propertyname) const override;
virtual int getFieldCount() const override;
virtual const char *getFieldName(int field) const override;
virtual int findField(const char *fieldName) const override;
virtual unsigned int getFieldTypeFlags(int field) const override;
virtual const char *getFieldTypeString(int field) const override;
virtual const char **getFieldPropertyNames(int field) const override;
virtual const char *getFieldProperty(int field, const char *propertyname) const override;
virtual int getFieldArraySize(void *object, int field) const override;
virtual std::string getFieldValueAsString(void *object, int field, int i) const override;
virtual bool setFieldValueAsString(void *object, int field, int i, const char *value) const override;
virtual const char *getFieldStructName(int field) const override;
virtual void *getFieldStructValuePointer(void *object, int field, int i) const override;
};
Register_ClassDescriptor(WaveShortMessageDescriptor);
WaveShortMessageDescriptor::WaveShortMessageDescriptor() : omnetpp::cClassDescriptor("WaveShortMessage", "omnetpp::cPacket")
{
propertynames = nullptr;
}
WaveShortMessageDescriptor::~WaveShortMessageDescriptor()
{
delete[] propertynames;
}
bool WaveShortMessageDescriptor::doesSupport(omnetpp::cObject *obj) const
{
return dynamic_cast<WaveShortMessage *>(obj)!=nullptr;
}
const char **WaveShortMessageDescriptor::getPropertyNames() const
{
if (!propertynames) {
static const char *names[] = { nullptr };
omnetpp::cClassDescriptor *basedesc = getBaseClassDescriptor();
const char **basenames = basedesc ? basedesc->getPropertyNames() : nullptr;
propertynames = mergeLists(basenames, names);
}
return propertynames;
}
const char *WaveShortMessageDescriptor::getProperty(const char *propertyname) const
{
omnetpp::cClassDescriptor *basedesc = getBaseClassDescriptor();
return basedesc ? basedesc->getProperty(propertyname) : nullptr;
}
int WaveShortMessageDescriptor::getFieldCount() const
{
omnetpp::cClassDescriptor *basedesc = getBaseClassDescriptor();
return basedesc ? 15+basedesc->getFieldCount() : 15;
}
unsigned int WaveShortMessageDescriptor::getFieldTypeFlags(int field) const
{
omnetpp::cClassDescriptor *basedesc = getBaseClassDescriptor();
if (basedesc) {
if (field < basedesc->getFieldCount())
return basedesc->getFieldTypeFlags(field);
field -= basedesc->getFieldCount();
}
static unsigned int fieldTypeFlags[] = {
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISEDITABLE,
FD_ISCOMPOUND,
FD_ISCOMPOUND,
FD_ISEDITABLE,
};
return (field>=0 && field<15) ? fieldTypeFlags[field] : 0;
}
const char *WaveShortMessageDescriptor::getFieldName(int field) const
{
omnetpp::cClassDescriptor *basedesc = getBaseClassDescriptor();
if (basedesc) {
if (field < basedesc->getFieldCount())
return basedesc->getFieldName(field);
field -= basedesc->getFieldCount();
}
static const char *fieldNames[] = {
"wsmVersion",
"securityType",
"channelNumber",
"dataRate",
"priority",
"psid",
"psc",
"wsmLength",
"wsmData",
"senderAddress",
"recipientAddress",
"serial",
"senderPos",
"gpspos",
"timestamp",
};
return (field>=0 && field<15) ? fieldNames[field] : nullptr;
}
Waveshortmessage.h
//Waveshortmessage.h
// Generated file, do not edit! Created by nedtool 5.0 from veins/modules/messages/WaveShortMessage.msg.
//
#ifndef __WAVESHORTMESSAGE_M_H
#define __WAVESHORTMESSAGE_M_H
#include <omnetpp.h>
// nedtool version check
#define MSGC_VERSION 0x0500
#if (MSGC_VERSION!=OMNETPP_VERSION)
# error Version mismatch! Probably this file was generated by an earlier version of nedtool: 'make clean' should help.
#endif
// cplusplus {{
** #include <stdint.h>
#include "veins/modules/mobility/traci/TraCIBuffer.h"
#include "veins/modules/mobility/traci/TraCICommandInterface.h"
#include "veins/modules/mobility/traci/TraCIConnection.h"
#include "veins/modules/mobility/traci/TraCIConstants.h"
#include "veins/modules/mobility/traci/TraCICoord.h" **
#include "veins/base/utils/Coord.h"
// }}
/**
* Class generated from <tt>veins/modules/messages/WaveShortMessage.msg:40</tt> by nedtool.
* <pre>
* packet WaveShortMessage
* {
* //Version of the Wave Short Message
* int wsmVersion = 0;
* //Determine which security mechanism was used
* int securityType = 0;
* //Channel Number on which this packet was sent
* int channelNumber;
* //Data rate with which this packet was sent
* int dataRate = 1;
* //Power Level with which this packet was sent
* int priority = 3;
* //Unique number to identify the service
* int psid = 0;
* //Provider Service Context
* string psc = "Service with some Data";
* //Length of Wave Short Message
* int wsmLength;
* //Data of Wave Short Message
* string wsmData = "Some Data";
*
* int senderAddress = 0;
* int recipientAddress = -1;
* int serial = 0;
* Coord senderPos;
*
* Veins::TraCICoord gpspos = omnet2traci(senderPos);
*
* simtime_t timestamp = 0;
*
* }
* </pre>
*/
class WaveShortMessage : public ::omnetpp::cPacket
{
protected:
int wsmVersion;
int securityType;
int channelNumber;
int dataRate;
int priority;
int psid;
::omnetpp::opp_string psc;
int wsmLength;
::omnetpp::opp_string wsmData;
int senderAddress;
int recipientAddress;
int serial;
Coord senderPos;
Veins::TraCICoord gpspos;
::omnetpp::simtime_t timestamp;
private:
void copy(const WaveShortMessage& other);
protected:
// protected and unimplemented operator==(), to prevent accidental usage
bool operator==(const WaveShortMessage&);
public:
WaveShortMessage(const char *name=nullptr, int kind=0);
WaveShortMessage(const WaveShortMessage& other);
virtual ~WaveShortMessage();
WaveShortMessage& operator=(const WaveShortMessage& other);
virtual WaveShortMessage *dup() const {return new WaveShortMessage(*this);}
virtual void parsimPack(omnetpp::cCommBuffer *b) const;
virtual void parsimUnpack(omnetpp::cCommBuffer *b);
// field getter/setter methods
virtual int getWsmVersion() const;
virtual void setWsmVersion(int wsmVersion);
virtual int getSecurityType() const;
virtual void setSecurityType(int securityType);
virtual int getChannelNumber() const;
virtual void setChannelNumber(int channelNumber);
virtual int getDataRate() const;
virtual void setDataRate(int dataRate);
virtual int getPriority() const;
virtual void setPriority(int priority);
virtual int getPsid() const;
virtual void setPsid(int psid);
virtual const char * getPsc() const;
virtual void setPsc(const char * psc);
virtual int getWsmLength() const;
virtual void setWsmLength(int wsmLength);
virtual const char * getWsmData() const;
virtual void setWsmData(const char * wsmData);
virtual int getSenderAddress() const;
virtual void setSenderAddress(int senderAddress);
virtual int getRecipientAddress() const;
virtual void setRecipientAddress(int recipientAddress);
virtual int getSerial() const;
virtual void setSerial(int serial);
virtual Coord& getSenderPos();
virtual const Coord& getSenderPos() const {return const_cast<WaveShortMessage*>(this)->getSenderPos();}
virtual void setSenderPos(const Coord& senderPos);
virtual Veins::TraCICoord& getGpspos();
virtual const Veins::TraCICoord& getGpspos() const {return const_cast<WaveShortMessage*>(this)->getGpspos();}
virtual void setGpspos(const Veins::TraCICoord& gpspos);
virtual ::omnetpp::simtime_t getTimestamp() const;
virtual void setTimestamp(::omnetpp::simtime_t timestamp);
**Coord traci2omnet(Veins::TraCICoord coord) const;
std::list<Coord> traci2omnet(const std::list<Veins::TraCICoord>&) const;
Veins::TraCICoord omnet2traci(Coord coord) const;
std::list<Veins::TraCICoord> omnet2traci(const std::list<Coord>&) const;**
};
inline void doParsimPacking(omnetpp::cCommBuffer *b, const WaveShortMessage& obj) {obj.parsimPack(b);}
inline void doParsimUnpacking(omnetpp::cCommBuffer *b, WaveShortMessage& obj) {obj.parsimUnpack(b);}
#endif // ifndef __WAVESHORTMESSAGE_M_H
Any help would be very appreciated. Thanks!
Currently I am working with localization in VANETs and I was facing the same problem.
As you can see in veins FAQ SUMO and OMNeT++ use different coordinate systems, so when you call mobility->getCurrentPosition() you get omnet coordinates not sumo coordinates.
I make some tests with proj4 C library and the values not was matching...
As me, probably you looking for the real sumo coordinates and for this you need call TraCIConnection::omnet2traci. But the problem is that not exists in veins a direct interface to access the object connection via TraCICommandInterface.
To overcome this trick I implemented one public method directly in the class TraCICommandInterface the signature of the method is the same of getLonLat method the diference is that inside I return the sumo coordinates calling the method `omnet2traci'. Now I can get the real sumo coordinates and use this for work with my real GPS dataset and one deadreckoning technique that I've implemented.
Follows the code of the method:
std::pair<double, double> TraCICommandInterface::getTraCIXY(const Coord& coord){
TraCICoord newCoord;
newCoord = connection.omnet2traci(coord);
return std::make_pair(newCoord.x, newCoord.y);
}
In your application class call this method using one TracICommandInterface object:
TraCIMobility* mobility;
TraCICommandInterface* traci;
Now in your initialize method instantiate this objects getting the active modules and traci interface:
mobility = TraCIMobilityAccess().get(getParentModule());
traci = mobility->getCommandInterface();
Now you will have this:
These are omnet++ cordinates:
Coord coordOmnet = mobility->getCurrentPosition();
These are sumo coordinates calling our implement method:
std::pair<double,double> coordTraCI = traci->getTraCIXY(mobility->getCurrentPosition());
Best Regards,
Pedro.
What is the main reason to convert the positions?
Why not use the OMNet/Veins - SUMO/TraCi coordinate?
So I was Playing around with c++11 Varidiacs, and I wanted to create a thing called CallClass, basically a class that warps a function, for later call,when all variables are set(truly I have No Idea If It can Be Useful):
#include <tuple>
template <typename OBJ,typename F,typename... VARGS>
class CallClass
{
public:
CallClass(OBJ& object,F callFunction)
:_object(&object),_func(callFunction)
{ }
CallClass(const CallClass& other)
:_func_args(other._func_args)
,_object(other._object)
,_func(other._func)
{ }
template <size_t INDEX>
auto get(){ return std::get<INDEX>(_func_args); }
template <size_t INDEX,typename T>
void set(const T& val){ std::get<INDEX>(_func_args) = val; }
template <size_t INDEX,typename T>
void set(T&& val){ std::get<INDEX>(_func_args) = val; }
auto Call()
{
//throws segmentation Fault Here
return InnerCall<0>(_func_args);
}
virtual ~CallClass() {}
protected:
private:
std::tuple<VARGS...> _func_args;
OBJ* _object;
F _func;
template <size_t INDEX,typename... ARGS>
auto InnerCall(std::tuple<VARGS...>& tup,ARGS... args)
{
auto arg = std::get<INDEX>(tup);
return InnerCall<INDEX + 1>(tup,args...,arg);
}
template <size_t INDEX,VARGS...>
auto InnerCall(std::tuple<VARGS...>& tup,VARGS... args)
{
return (_object->*_func)(args...);
}
};
Now when I try to compile(compiling using IDE:code::blocks, configured to use MINGW On windows ), it prints Compiler:Segmentation Fault, anybody any Ideas?
Usage:
class obj{
public:
obj(int a)
:_a(a)
{ }
virtual ~obj() {}
int add(int b,int c){
return _a + b + c;
}
private:
int _a;
};
int main(){
obj ob(6);
CallClass<obj,decltype(obj::add),int,int> callAdd(ob,obj::add);
callAdd.set<0,int>(5);
callAdd.set<1,int>(7);
cout << "result is " << callAdd.Call() << endl;
return 0;
}
After a Bit of a search i stumbled upon a similar issue, in a way.
apparently the way I'm unpacking the tuple is an issue, so i decided to use a different approach as shown in: enter link description here
had to add a few changes to suit my needs:
changes:
namespace detail
{
template <typename OBJ,typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static auto call(OBJ& obj,F f, Tuple && t)
{
return call_impl<OBJ,F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(obj,f, std::forward<Tuple>(t));
}
};
template <typename OBJ,typename F, typename Tuple, int Total, int... N>
struct call_impl<OBJ,F, Tuple, true, Total, N...>
{
static auto call(OBJ& obj,F f, Tuple && t)
{
return (obj.*f)(std::get<N>(std::forward<Tuple>(t))...);
}
};
}
// user invokes this
template <typename OBJ,typename F, typename Tuple>
auto call(OBJ& obj,F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
return detail::call_impl<OBJ,F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(obj,f, std::forward<Tuple>(t));
}
and changed Call():
auto Call()
{
std::tuple<VARGS...> func_args = _func_args;
return call(*_object,_func, std::move(func_args));
}
I will probably make a few more changes, like passing the tuple as a reference, and making the structs a part of my class.
In std::map, this ends up causing an error when the first object is constructed. I've checked the debugger, and I see that free_list::init() creates the consecutive memory addresses correctly. I'm aware this allocator cannot be used in vector or other related containers, but it's only meant to work with the nodular containers.
I get a run-time error from this in xutility (in VC12), at line 158:
_Container_proxy *_Parent_proxy = _Parent->_Myproxy;
Checking the debugger, it appears that _Parent was never initialized, bringing about the 0xC0000005 run-time error. Why or how it didn't get initialized and why this occurred when the first object was being constructed (after std::map did 3 separate allocations), I do not know.
I would like to have this work with std::map and std::list and the other nodular containers and am not worried about whether it can perform in std::vector, etc.
#include <algorithm>
class free_list {
public:
free_list() {}
free_list(free_list&& other)
: m_next(other.m_next) {
other.m_next = nullptr;
}
free_list(void* data, std::size_t num_elements, std::size_t element_size) {
init(data, num_elements, element_size);
}
free_list& operator=(free_list&& other) {
m_next = other.m_next;
other.m_next = nullptr;
}
void init(void* data, std::size_t num_elements, std::size_t element_size) {
union building {
void* as_void;
char* as_char;
free_list* as_self;
};
building b;
b.as_void = data;
m_next = b.as_self;
b.as_char += element_size;
free_list* runner = m_next;
for (std::size_t s = 1; s < num_elements; ++s) {
runner->m_next = b.as_self;
runner = runner->m_next;
b.as_char += element_size;
}
runner->m_next = nullptr;
}
free_list* obtain() {
if (m_next == nullptr) {
return nullptr;
}
free_list* head = m_next;
m_next = head->m_next;
return head;
}
void give_back(free_list* ptr) {
ptr->m_next = m_next;
m_next = ptr;
}
free_list* m_next;
};
template<class T>
class pool_alloc {
typedef pool_alloc<T> myt;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef std::false_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
template<class U> struct rebind {
typedef pool_alloc<U> other;
};
~pool_alloc() {
destroy();
}
pool_alloc() : data(nullptr), fl(), capacity(4096) {
}
pool_alloc(size_type capacity) : data(nullptr), fl(), capacity(capacity) {}
pool_alloc(const myt& other)
: data(nullptr), fl(), capacity(other.capacity) {}
pool_alloc(myt&& other)
: data(other.data), fl(std::move(other.fl)), capacity(other.capacity) {
other.data = nullptr;
}
template<class U>
pool_alloc(const pool_alloc<U>& other)
: data(nullptr), fl(), capacity(other.max_size()) {}
myt& operator=(const myt& other) {
destroy();
capacity = other.capacity;
}
myt& operator=(myt&& other) {
destroy();
data = other.data;
other.data = nullptr;
capacity = other.capacity;
fl = std::move(other.fl);
}
static pointer address(reference ref) {
return &ref;
}
static const_pointer address(const_reference ref) {
return &ref;
}
size_type max_size() const {
return capacity;
}
pointer allocate(size_type) {
if (data == nullptr) create();
return reinterpret_cast<pointer>(fl.obtain());
}
void deallocate(pointer ptr, size_type) {
fl.give_back(reinterpret_cast<free_list*>(ptr));
}
template<class... Args>
static void construct(pointer ptr, Args&&... args) {
::new (ptr) T(std::forward<Args>(args)...);
}
static void destroy(pointer ptr) {
ptr->~T();
}
bool operator==(const myt& other) const {
return reinterpret_cast<char*>(data) ==
reinterpret_cast<char*>(other.data);
}
bool operator!=(const myt& other) const {
return !operator==(other);
}
private:
void create() {
data = ::operator new(capacity * sizeof(value_type));
fl.init(data, capacity, sizeof(value_type));
}
void destroy() {
::operator delete(data);
data = nullptr;
}
void* data;
free_list fl;
size_type capacity;
};
template<>
class pool_alloc < void > {
public:
template <class U> struct rebind { typedef pool_alloc<U> other; };
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
};
The problem comes when std::pair is being constructed (in MSVC12 utility at line 214):
template<class _Other1,
class _Other2,
class = typename enable_if<is_convertible<_Other1, _Ty1>::value
&& is_convertible<_Other2, _Ty2>::value,
void>::type>
pair(_Other1&& _Val1, _Other2&& _Val2)
_NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1&&>::value
&& is_nothrow_constructible<_Ty2, _Other2&&>::value))
: first(_STD forward<_Other1>(_Val1)),
second(_STD forward<_Other2>(_Val2))
{ // construct from moved values
}
Even after stepping in, the run-time error occurs, the same as described above with _Parent not being initialized.
I was able to answer my own question through extensive debugging. Apparently, VC12's std::map implementation at least at times will cast an _Alnod (permanent allocator that stays in scope for the life of the map, which is used to allocate and deallocate the nodes in the map, what I'd expect to be what actually calls allocate() and deallocate()) as an _Alproxy, a temporary allocator which creates some sort of object called _Mproxy (or something like that) using allocate(). The problem, though, is that VC12's implementation then lets _Alproxy go out of scope while still expecting the pointer to the allocated object to remain valid, so it is clear then that I would have to use ::operator new and ::operator delete on an object like _Mproxy: using a memory pool that then goes out of scope while a pointer to a location in it remains is what causes the crash.
I came up with what I suppose could be called a dirty trick, a test that is performed when copy-constructing or copy-assigning an allocator to another allocator type:
template<class U>
pool_alloc(const pool_alloc<U>& other)
: data(nullptr), fl(), capacity(other.max_size()), use_data(true) {
if (sizeof(T) < sizeof(U)) use_data = false;
}
I added the bool member use_data to the allocator class, which if true means to use the memory pool and which if false means to use ::operator new and ::operator delete. By default, it is true. The question of its value arises when the allocator gets cast as another allocator type whose template parameter's size is smaller than that of the source allocator; in that case, use_data is set to false. Because this _Mproxy object or whatever it's called is rather small, this fix seems to work, even when using std::set with char as the element type.
I've tested this using std::set with type char in both VC12 and GCC 4.8.1 in 32-bit and have found that in both cases it works. When allocating and deallocating the nodes in both cases, the memory pool is used.
Here is the full source code:
#include <algorithm>
class free_list {
public:
free_list() {}
free_list(free_list&& other)
: m_next(other.m_next) {
other.m_next = nullptr;
}
free_list(void* data, std::size_t num_elements, std::size_t element_size) {
init(data, num_elements, element_size);
}
free_list& operator=(free_list&& other) {
if (this != &other) {
m_next = other.m_next;
other.m_next = nullptr;
}
return *this;
}
void init(void* data, std::size_t num_elements, std::size_t element_size) {
union building {
void* as_void;
char* as_char;
free_list* as_self;
};
building b;
b.as_void = data;
m_next = b.as_self;
b.as_char += element_size;
free_list* runner = m_next;
for (std::size_t s = 1; s < num_elements; ++s) {
runner->m_next = b.as_self;
runner = runner->m_next;
b.as_char += element_size;
}
runner->m_next = nullptr;
}
free_list* obtain() {
if (m_next == nullptr) {
return nullptr;
}
free_list* head = m_next;
m_next = head->m_next;
return head;
}
void give_back(free_list* ptr) {
ptr->m_next = m_next;
m_next = ptr;
}
free_list* m_next;
};
template<class T>
class pool_alloc {
typedef pool_alloc<T> myt;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef std::false_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
myt select_on_container_copy_construction() const {
return *this;
}
template<class U> struct rebind {
typedef pool_alloc<U> other;
};
~pool_alloc() {
clear();
}
pool_alloc() : data(nullptr), fl(), capacity(4096), use_data(true) {}
pool_alloc(size_type capacity) : data(nullptr), fl(),
capacity(capacity), use_data(true) {}
pool_alloc(const myt& other)
: data(nullptr), fl(), capacity(other.capacity),
use_data(other.use_data) {}
pool_alloc(myt&& other)
: data(other.data), fl(std::move(other.fl)), capacity(other.capacity),
use_data(other.use_data) {
other.data = nullptr;
}
template<class U>
pool_alloc(const pool_alloc<U>& other)
: data(nullptr), fl(), capacity(other.max_size()), use_data(true) {
if (sizeof(T) < sizeof(U)) use_data = false;
}
myt& operator=(const myt& other) {
if (*this != other) {
clear();
capacity = other.capacity;
use_data = other.use_data;
}
}
myt& operator=(myt&& other) {
if (*this != other) {
clear();
data = other.data;
other.data = nullptr;
capacity = other.capacity;
use_data = other.use_data;
fl = std::move(other.fl);
}
return *this;
}
template<class U>
myt& operator=(const pool_alloc<U>& other) {
if (this != reinterpret_cast<myt*>(&other)) {
capacity = other.max_size();
if (sizeof(T) < sizeof(U))
use_data = false;
else
use_data = true;
}
return *this;
}
static pointer address(reference ref) {
return &ref;
}
static const_pointer address(const_reference ref) {
return &ref;
}
size_type max_size() const {
return capacity;
}
pointer allocate(size_type) {
if (use_data) {
if (data == nullptr) create();
return reinterpret_cast<pointer>(fl.obtain());
} else {
return reinterpret_cast<pointer>(::operator new(sizeof(T)));
}
}
void deallocate(pointer ptr, size_type) {
if (use_data) {
fl.give_back(reinterpret_cast<free_list*>(ptr));
} else {
::operator delete(reinterpret_cast<void*>(ptr));
}
}
template<class... Args>
static void construct(pointer ptr, Args&&... args) {
::new ((void*)ptr) value_type(std::forward<Args>(args)...);
}
static void destroy(pointer ptr) {
ptr->~value_type();
}
bool operator==(const myt& other) const {
return reinterpret_cast<char*>(data) ==
reinterpret_cast<char*>(other.data);
}
bool operator!=(const myt& other) const {
return !operator==(other);
}
private:
void create() {
size_type size = sizeof(value_type) < sizeof(free_list*) ?
sizeof(free_list*) : sizeof(value_type);
data = ::operator new(capacity * size);
fl.init(data, capacity, size);
}
void clear() {
::operator delete(data);
data = nullptr;
}
void* data;
free_list fl;
size_type capacity;
bool use_data;
};
template<>
class pool_alloc < void > {
public:
template <class U> struct rebind { typedef pool_alloc<U> other; };
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
};
template<class Container, class Alloc>
void change_capacity(Container& c, typename Alloc::size_type new_capacity) {
Container temp(c, Alloc(new_capacity));
c = std::move(temp);
}
Since the allocator is not automatic-growing (don't know how to make such a thing), I have added the change_capacity() function.