Say I have a Storage class:
class Storage
{
public:
const string& get() const { return m_data; }
const char& get(int ind) const { return m_data[ind]; }
const string& get(int s_ind, int e_ind) const { /* TBD */ }
private:
string m_data; ///< Data is so big that part of it is stored on disk
}
Say I have a Writer class that gets const Storage& and needs to access its data.
My question, is there a way to implement:
const string& get(int s_ind, int e_ind) const;
i.e, get const access to only a part of a string.
Notes:
get() is called countless of times and it is the bottleneck of my application. I'd like to avoid allocating new objects when accessing data.
is there a way to implement:
const string& get(int s_ind, int e_ind) const;
i.e, get const access to only a part of a string.
Definitely not.
What is often done - and may resolve your bottleneck - is to create a class that stores a const char* and size_t (or equally begin and end const char*s, or iterators but there's no reason to limit this to use for data in std::strings).
You could then create an object that "references" text inside a string, and use it until any of the events that would invalidate an iterator or reference to those characters happens - see the Standard or e.g. cppreference. It's possible to support stream output, comparisons, indexing etc. driven off the std::string hosted data.
Clearly you won't be able to pass such a class to functions that hardcode std::string type, but you could write it to have a similar interface, which should lessen pain.
Just as a taster (hasn't seen a compiler / flesh out as needed)...
class Text_Ref
{
public:
Text_Ref(const char* p, size_t n) : p_(p), n_(n) { }
// intuitive values for &text_ref[x] BUT text_ref[n] may not be nul
const char& operator[](size_t o) const { return p_[n]; }
*** OR ***
// text_ref[n] is nul BUT can't use &text_ref[x]
char operator[](size_t o) const { return o == n ? '\0' : p_[n]; }
// same design trade off as the operator[] alternatives above
char at(size_t o) const
{
if (o > n) throw std::out_of_range();
return o == n ? '\0' : p_[n];
}
bool empty() const { return n == 0; }
size_t size() const { return n; }
size_t length() const { return n; }
int compare(const char* p) const
{
do
{
if (*p != *p_)
return (int)*p_ - *p;
} while (*p);
return 0;
}
bool operator< (const char* p) const { return compare(p) < 0; }
bool operator<=(const char* p) const { return compare(p) <= 0; }
bool operator==(const char* p) const { return compare(p) == 0; }
bool operator!=(const char* p) const { return compare(p) != 0; }
bool operator>=(const char* p) const { return compare(p) >= 0; }
bool operator> (const char* p) const { return compare(p) > 0; }
private:
const char* p_;
size_t n;
};
inline std::ostream& operator<<(std::ostream& os, const Text_Ref& t)
{
return os.write(t.data(), t.size());
}
Related
I recently started c++ programming. I shifted from Java.
I was building my own Iterable class template like this:
template<class T> class Iterable
{
T start,stop;
public:
explicit Iterable(T s,T e) {start=s; stop=e;;}
public:
virtual void next(T& i) =0;
public:
class iterator: public std::iterator<
std::input_iterator_tag, // iterator_category
T, // value_type
long, // difference_type
const T*, // pointer
T // reference
>{
T current;
Iterable<T>* obj;
public:
explicit iterator(T t,Iterable<T>* o) : obj(o) {current=t;}
iterator& operator++() {obj->next(current); return *this;}
iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
bool operator==(iterator other) const {return current == other.current;}
bool operator!=(iterator other) const {return !(*this == other);}
const T& operator*() const {return current;}
};
iterator begin() {return iterator(start,this);}
iterator end() {return iterator(stop,this);}
};
When i tried to use this iterator, I got different results when invoked differently:
for(auto S=SI.begin();S!=SI.end();S++)
{
cout << *S << "\n";
//cout << contains(seqs,S) << "\n";
if(!contains(seqs,*S))
seqs.push_back(*(new Sequence(*S)));
}
gave different results from:
for(Sequence S : SI)
{
cout << S << "\n";
//cout << contains(seqs,S) << "\n";
if(!contains(seqs,S))
seqs.push_back(*(new Sequence(S)));
}
even in the loop.
My SeqIter class (SI is object of this class) is as follows:
class SeqIter : public flex::Iterable<Sequence>
{
int n;
public:
SeqIter(int s) : Iterable(Sequence(copyList(0,s),s),Sequence(copyList(3,s),s)) {n=s;}
void next(Sequence& s)
{
char ch;
for(int i=0;i<n;i++)
{
ch=nextBase(s[i]);
s[i]=ch;
if(ch!=0)
break;
}
}
};
Sorry if this is too much code, but I do not know how much code is required.
Also, a brief explanation on the Sequence class:
It is a class that has an array of numbers (in this case I tried with 3), and it generates next sequences based on the first, i.e. 000, 100, 200, 300; 010,110 ...
Each digit ranges from 0-3 (both included)
I am unable to understand why both loops give different sequences (first gives 000 100 200 300 010 110 whereas second gives 000 100 200 300 000 110)
I thought both the loops were fundamentally same, and that the first was just the expansion of the second. Is that not so?
Also sequence class: (Sorry for delay, but I guess this is the problem)
class Sequence
{
int size=1;
char* bps;
public:
Sequence() {size=0;}
Sequence(int s)
{
size=s;
bps=new char[s];
}
Sequence(char* arr,int s)
{
size=s;
bps=arr;
}
Sequence(const Sequence& seq)
{
size=seq.size;
bps=new char[size];
strcpy(bps,seq.bps);
}
String toString() const {return *(new String(bps,size));}
inline char* toCharArray() {return bps;}
inline int getSize() const {return size;}
//operator overloading
public:
bool operator==(const Sequence& s2) const
{
if(s2.size!=size)
return false;
String r1=toString();
String r2=s2.toString();
return (r1==r2 || r1==r2.reverse());
}
inline bool operator!=(const Sequence& s2) const {return !operator==(s2);}
const char& operator[](int n) const
{
if(n>=size)
throw commons::IndexOutOfBoundsException(n,size);
return bps[n];
}
char& operator[](int n)
{
if(n>=size)
throw commons::IndexOutOfBoundsException(n,size);
return bps[n];
}
Sequence& operator=(const Sequence& seq)
{
size=seq.size;
bps=new char[size];
strcpy(bps,seq.bps);
}
};
Sorry everyone. Answering my own question after debugging:
In my Sequence class, I was using strcpy in copying char*, where the array did not end with a '\0'
Probably that caused the error:
I read online a bit more to find that the expansion was as follows:
for(Sequence S : seqs)
{
...
}
is equivalent to
for(auto i=SI.begin();i!=SI.end();i++)
{
Sequence S=*i;
...
}
So in the assignment, (S=*i) the data was not properly copied.
Sorry for all the trouble
fixed by removing assignment operator overload, and changing copy-constructor to:
Sequence(const Sequence& seq)
{
size=seq.size;
bps=new char[size];
for(int i=0;i<size;i++)
bps[i]=seq[i];
}
I have trying to use a class as a key in an std::map. I have read documentations and I know I have to type some sort of sorting rule because my std::map is a binary search tree. The problem arise because the class key have another classes in it. Can someone get me some advice how to build the operators?
MasterRenderer file
std::map<TexturedModel, std::vector<Entity>> entites;
void MasterRenderer::processEntity(Entity entity)
{
TexturedModel model = entity.getModel();
auto search = entites.find(model);
if (search != entites.end()) {
//found
entites[model].emplace_back(entity);
}
else {
//not found
entites[model].emplace_back(entity);
}
std::cout << entites[model].size() << std::endl;
}
TexturedModel.h
TexturedModel(RawModel model, ModelTextures
texture)
:m_model(model), m_texture(texture) {
};
friend bool operator<(const TexturedModel& m,
const
TexturedModel& m2) {
return m.m_model < m2.m_model || m.m_model ==
m2.m_model && m.m_texture < m2.m_texture;
}
private:
RawModel m_model;
ModelTextures m_texture;
};
Rawmodel.h
unsigned int VaoID;
unsigned int Vertecies;
RawModel(unsigned int vaoID, unsigned int
vertecies)
:VaoID(vaoID), Vertecies(vertecies) {};
friend bool operator <(const RawModel& rhs, const
RawModel& rhs2)
{
return rhs.get() < rhs2.get();
}
friend bool operator ==(const RawModel& rhs, const
RawModel& rhs2)
{
return rhs.get() == rhs2.get();
}
const RawModel* get() const {
return this;
}
ModelTextures.h
ModelTextures(unsigned int ID)
:textureID(ID) {};
friend bool operator<(const ModelTextures& rhs,
const ModelTextures& rhs2)
{
return rhs.get() < rhs2.get();
}
const ModelTextures* get() const{
return this;
}
private:
unsigned int textureID;
float shineDamper = 1.0f;
float reflectivity = 0.0f;
};
friend bool operator<(const ModelTextures& rhs,
const ModelTextures& rhs2)
{
return rhs.get() < rhs2.get();
}
const ModelTextures* get() const{
return this;
}
this orders by address of the object, not content. That violates the requirements of std::map.
friend auto as_tie(const ModelTexture& m) {
return std::tie(m.textureID, m.shineDamper, m.reflexivity);
}
friend bool operator<(const ModelTextures& rhs,
const ModelTextures& rhs2)
{
return as_tie(rhs) < as_tie(lhs);
}
repeat this pattern for TexturedModel and RawModel.
If you are stuck in c++11 you have to manually write the return type of as_tie or use decltype.
friend auto as_tie(const ModelTexture& m)
-> decltype(std::tie(m.textureID, m.shineDamper, m.reflexivity))
{
return std::tie(m.textureID, m.shineDamper, m.reflexivity);
}
I have a class which holds small numbers inside bigger integer variable. It works fine and fast and looks like this:
template
class Container<IntegerT>
static int bitsPerElement;
IntegerT data; // [0000] [0000] [0000] [0000] up to 128bits(or maybe more)
int size;
iterator as value_type return "reference" to container element:
Container::iterator
DataRef operator*()
DataRef
Container* parent;
int position;
But i got a problem of unavailability of std::sort, because it have no clue how to actually swap elements of this container (direct swapping of DataRefs is obviously pointless).
Is there any magic way to make std::sort work with it (actually to force it use custom swap function)?
Or is there decent alternative to std::sort which can handle this situation? (storing DataRefs in array is not considered as a solution)
Which is the fastest way to sort this data structure?
#ifndef INTSTORAGE_H
#define INTSTORAGE_H
#include <algorithm>
template<class T> class IntStorage;
template<class T>
class DataRef
{
public:
DataRef(IntStorage<T>* parent, int position) : m_parent(parent), m_position(position) {}
DataRef(DataRef&& o) = default;
DataRef(const DataRef& o) = default;
int value() const {return m_parent->value(m_position);}
void setValue(int value) {m_parent->setValue(m_position, value);}
DataRef& operator=(const DataRef& c)
{ setValue(c.value()); return *this; }
DataRef& operator=(const DataRef&& c)
{ setValue(c.value()); return *this; }
bool operator<(const DataRef& o) const
{ return value() < o.value(); }
IntStorage<T>* m_parent;
int m_position;
};
template<class T>
class IntStorage
{
template<typename> friend class IntStorage;
template<typename> friend class DataRef;
public:
void append(int value)
{
data |= (static_cast<T>(value) << (s_bitsPerItem * size));
++size;
}
void setValue(int index, T value)
{
data = ((~(s_mask << (s_bitsPerItem * index))) & data)
| (static_cast<T>(value) << (s_bitsPerItem * index));
}
T value(int i) const { return (data & s_mask << (i * s_bitsPerItem)) >> (i * s_bitsPerItem); }
class iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = int;
using value_type = DataRef<T>;
using pointer = DataRef<T>*;
using reference = DataRef<T>&;
iterator(IntStorage<T>* parent, int pos = 0) : ref(parent, pos) {}
inline bool operator==(const iterator& o) const { return ref.m_parent == o.ref.m_parent && ref.m_position == o.ref.m_position;}
inline bool operator!=(const iterator& o) const { return !operator==(o);}
inline const DataRef<T>& operator*() const { return ref;}
inline DataRef<T>& operator*() { return ref; }
inline iterator& operator++() { ++ref.m_position; return *this; }
inline iterator& operator--() { --ref.m_position; return *this; }
inline int operator-(const iterator& o) const { return ref.m_position - o.ref.m_position; }
inline iterator operator+(int diff) const { return iterator(ref.m_parent, ref.m_position + diff); }
inline iterator operator-(int diff) const { return iterator(ref.m_parent, ref.m_position - diff); }
inline bool operator<(const iterator& o) const { return ref.m_position < o.ref.m_position; }
DataRef<T> ref;
};
friend class iterator;
iterator begin() {return iterator(this, 0);}
iterator end() {return iterator(this, size);}
iterator cbegin() {return iterator(this, 0);}
iterator cend() {return iterator(this, size);}
static constexpr T s_mask = 0b111111;
static constexpr int s_bitsPerItem = 6;
int size = 0;
T data = 0;
};
#endif // INTSTORAGE_H
I'm writing my own typesafe enum header-only library at https://bitbucket.org/chopsii/typesafe-enums
The idea is to replace the non-type-safe c-style enum like:
enum ItemCategory
{
BLOCK,
WEAPON
};
with something that's properly type safe.
So far, my solution uses a macro that, for an example equivalent to the above enum, looks like this:
TypesafeEnum(ItemCategory,
(BLOCK)
(WEAPON)
);
And expands to something that looks like this:
template<typename InnerType>
class Wrapped {
public:
InnerType getValue() const { return _val; }
bool operator<(const Wrapped<InnerType>& rhs) const { ; return _val < rhs._val; }
bool operator>(const Wrapped<InnerType>& rhs) const { ; return _val > rhs._val; }
bool operator==(const Wrapped<InnerType>& rhs) const { ; return _val == rhs._val; }
private:
InnerType _val;
protected:
explicit Wrapped<InnerType>(const InnerType& val) : _val(val) {}
void setValue(const InnerType& val) { _val = val; }
};
class WrappedTypeItemCategory : private Wrapped<int>
{
private:
typedef const std::string* strptr;
typedef const std::string* const cstrptr;
explicit WrappedTypeItemCategory(const std::string& label, int val): Wrapped<int>(val), str(&label)
{}
cstrptr str;
public:
static WrappedTypeItemCategory make(const std::string& label, int val)
{
return WrappedTypeItemCategory(label, val);
}
void operator=(const WrappedTypeItemCategory& rhs)
{
;
setValue(rhs.getValue());
const_cast<strptr>(str) = rhs.str;
}
int getValue() const
{
return Wrapped<int>::getValue();
}
const std::string& getString() const
{
return *str;
}
bool operator<(const WrappedTypeItemCategory & rhs) const
{
;
return getValue() < rhs.getValue();
}
bool operator>(const WrappedTypeItemCategory & rhs) const
{
;
return getValue() > rhs.getValue();
}
bool operator==(const WrappedTypeItemCategory & rhs) const
{
;
return getValue() == rhs.getValue();
}
friend std::ostream & operator<<(std::ostream &os, const WrappedTypeItemCategory& rhs)
{
;
return os << *rhs.str << "(" << rhs.getValue() << ")";
}
};
;
namespace {
template<typename T> class ItemCategoryInner : public TypesafeEnumBase
{
public:
static const WrappedTypeItemCategory BLOCK;
static const WrappedTypeItemCategory WEAPON;
static const std::string BLOCKStr;
static const std::string WEAPONStr;
};
template<typename T> const WrappedTypeItemCategory ItemCategoryInner<T>::BLOCK = WrappedTypeItemCategory::make(ItemCategoryInner<T>::BLOCKStr, 0);
template<typename T> const WrappedTypeItemCategory ItemCategoryInner<T>::WEAPON = WrappedTypeItemCategory::make(ItemCategoryInner<T>::WEAPONStr, 1);
template<typename T> const std::string ItemCategoryInner<T>::BLOCKStr("ItemCategory::BLOCK");
template<typename T> const std::string ItemCategoryInner<T>::WEAPONStr("ItemCategory::WEAPON");
struct ItemCategoryTemplateConstantTrick
{};
};
class ItemCategory : public ItemCategoryInner<ItemCategoryTemplateConstantTrick>
{
private:
const WrappedTypeItemCategory* const val;
public:
class InvalidValueError : public std::runtime_error
{
public:
const int val;
InvalidValueError(int val): std::runtime_error(std::string("Invalid value given for ") + "ItemCategory::make"), val(val)
{}
};
ItemCategory(const WrappedTypeItemCategory& value): val(&value)
{}
void operator=(const ItemCategory& rhs)
{
const_cast<const WrappedTypeItemCategory*>(val) = rhs.val;
}
static ItemCategory make(const int& val)
{
if (val == ItemCategory::BLOCK.getValue()) return ItemCategory(ItemCategory::BLOCK);
if (val == ItemCategory::WEAPON.getValue()) return ItemCategory(ItemCategory::WEAPON);
;
throw InvalidValueError(val);
}
const WrappedTypeItemCategory* const getWrappedValue() const
{
return val;
}
int getValue() const
{
return val->getValue();
}
const std::string & getString() const
{
return val->getString();
}
bool operator<(const ItemCategory& rhs) const
{
return *val < *rhs.val;
}
bool operator>(const ItemCategory& rhs) const
{
return *val > *rhs.val;
}
bool operator==(const WrappedTypeItemCategory& rhs) const
{
return *val == rhs;
}
bool operator!=(const WrappedTypeItemCategory& rhs) const
{
return !(*val == rhs);
}
bool operator<=(const WrappedTypeItemCategory& rhs) const
{
return (*val == rhs || *val < rhs);
}
bool operator>=(const WrappedTypeItemCategory& rhs) const
{
return (*val == rhs || *val > rhs);
}
void print(std::ostream& os) const override
{
os << *val;
}
friend std::ostream & operator<<(std::ostream &os, const ItemCategory& rhs)
{
rhs.print(os);
return os;
}
};
;
If I manually pre-expand it, like I have done here - by pre-compiling to file - then intellisense handles it all up until the line that says:
class ItemCategory : public ItemCategoryInner<ItemCategoryTemplateConstantTrick>
At which point it starts thinking ItemCategoryInner and ItemCategoryTemplateConstantTrick are ambiguous, along with many other things on every few lines of the file.
The header that contains this code is included in many places. I know I'm violating the One Definition Rule, which is why I'm using the Template Constant Trick, but I think I need to violate the ODR as my goal is to have an easy to use Macro based typesafe replacement for C++ enums.
I'm not sure if it's the violation of ODR that is the cause of my issues, or something else. I tried __declspec(selectany) but it didn't seem to help - and I would prefer if this macro would be eventually cross-platform, because if it works out, I have other projects I would use it in.
Either way, the .cpp files etc that make use of the enum are able to, and intellisense correctly suggests the options.
However, on a possibly related note, if I don't pre-expand the macro, intellisense isn't able to parse it and it doesn't know what a ItemCategory is at all, even though it compiles and works fine.
I just want my intellisense to work properly with my typesafe enums - it slows down intellisense and confuses it in other code in the same project.
For stupid reasons, I'd like to write a function with the following signature (in which the (^) represents Apple's "blocks" extension to C++):
extern "C" my_qsort_b(void *arr, size_t nelem, size_t eltsize, int (^)(const void *, const void *));
where the function is implemented in terms of std::sort. (Note that I can't use qsort because it takes a function pointer, not a block pointer; and I can't use qsort_b because I might not have Apple's standard library. I won't accept answers that involve qsort_b.)
Is it possible to implement this function in C++ using std::sort? Or do I have to write my own quicksort implementation from scratch?
Please provide working code. The devil is in the details here; I'm not asking "How do I use std::sort?"
Doing this is harder than it seems it should be — although std::sort is clearly more powerful than qsort, the impedance mismatch between the two is sufficient to make implementing the latter in terms of the former a daunting task.
Still, it can be done. Here is a working implementation of my_qsort_b (here called block_qsort) that uses std::sort as the workhorse. The code is adapted from an implementation of qsort in terms of std::sort done as an exercise, and trivially modified to compare by invoking a block. The code is tested to compile and work with clang++ 3.3 on x86_64 Linux.
#include <algorithm>
#include <cstring>
struct Elem {
char* location;
size_t size;
bool needs_deleting;
Elem(char* location_, size_t size_):
location(location_), size(size_), needs_deleting(false) {}
Elem(const Elem& rhs): size(rhs.size) {
location = new char[size];
*this = rhs;
needs_deleting = true;
}
Elem& operator=(const Elem& rhs) {
memcpy(location, rhs.location, size);
return *this;
}
~Elem() {
if (needs_deleting)
delete[] location;
}
};
struct Iter: public std::iterator<std::random_access_iterator_tag, Elem> {
Elem elem;
Iter(char* location, size_t size): elem(location, size) {}
// Must define custom copy/assignment to avoid copying of iterators
// making copies of elem.
Iter(const Iter& rhs): elem(rhs.elem.location, rhs.elem.size) {}
Iter& operator=(const Iter& rhs) {elem.location = rhs.elem.location; return *this;}
char* adjust(ptrdiff_t offset) const {
return elem.location + ptrdiff_t(elem.size) * offset;
}
// Operations required for random iterator.
Iter operator+(ptrdiff_t diff) const {return Iter(adjust(diff), elem.size);}
Iter operator-(ptrdiff_t diff) const {return Iter(adjust(-diff), elem.size);}
ptrdiff_t operator-(const Iter& rhs) const {
return (elem.location - rhs.elem.location) / ptrdiff_t(elem.size);
}
Iter& operator++() {elem.location=adjust(1); return *this;}
Iter& operator--() {elem.location=adjust(-1); return *this;}
Iter operator++(int) {Iter old = *this; ++*this; return old;}
Iter operator--(int) {Iter old = *this; --*this; return old;}
bool operator!=(const Iter& rhs) const {return elem.location != rhs.elem.location;}
bool operator==(const Iter& rhs) const {return elem.location == rhs.elem.location;}
bool operator<(const Iter& rhs) const {return elem.location < rhs.elem.location;}
Elem& operator*() {return elem;}
};
struct Cmp_adaptor {
typedef int (^Qsort_comparator)(const void*, const void*);
Qsort_comparator cmp;
Cmp_adaptor(Qsort_comparator cmp_) : cmp(cmp_) {}
bool operator()(const Elem& a, const Elem& b) {
return cmp(a.location, b.location) < 0;
}
};
void block_qsort(void* base, size_t nmemb, size_t size,
int (^compar)(const void *, const void *))
{
Iter begin = Iter(static_cast<char*>(base), size);
std::sort(begin, begin + nmemb, Cmp_adaptor(compar));
}
If block_qsort needs to be called from C, you can declare it extern "C", since it uses no C++ features in its interface. To test the function, compile and run this additional code:
// test block_qsort
#include <iostream>
#include <cstring>
int main(int argc, char** argv)
{
// sort argv[1..argc].
block_qsort(argv + 1, argc - 1, sizeof (char*),
^int (const void* a, const void* b) {
return strcmp(*(char**) a, *(char**) b);
});
for (++argv; *argv; argv++)
std::cout << *argv << std::endl;
return 0;
}
to use std::sort, you'd have to write an iterator class and a class that wraps the block in a functor object. Implementing quicksort by yourself seems like a shorter alternative.
BTW: the block should be returning bool, not void, right?
Start with this:
struct memblockref {
void* location;
size_t size;
memblockref( void* loc, size_t s ):location(loc), size(s) {}
memblockref& operator=( memblockref const& right ) {
Assert( size == right.size );
memcpy( location, right.location, std::min( size, right.size ));
return *this;
}
private:
memblockref( memblockref const& ) = delete; // or leave unimplemented in C++03
memblockref() = delete; // or leave unimplemented in C++03
};
then use http://www.boost.org/doc/libs/1_52_0/libs/iterator/doc/iterator_facade.html to create iterators of memblockref to your memory buffer.
Then turn the block into a function pointer, or wrap it in a lambda or functor, and call std::sort, where you call your block based comparison on the location field of the left and right memblockref.
You may have to specialize swap or iter_swap as well, but maybe not.