Related
I am creating multiple different types of encoders where the main difference is the different data structures used to initialize the class. My header is something like this
struct tagTypeInfo {
uint16_t start;
uint16_t last;
uint16_t count;
std::string name;
rdwrT rdwr;
};
template <typename T>
class encodedTag
{
public:
encodedTag(vector<tagTypeInfo> tagInfo_) : tagInfo(tagInfo_)
{
int start = 0;
for(auto & tag : tagInfo)
{
tag.start = start;
tag.last = start + tag.count - 1;
start = start + tag.count;
}
}
uint16_t encode(uint16_t tag, T tagType)
{
assert(tag<tagInfo[tagType].count)
return( tagInfo[tagType].start + tag );
}
std::tuple<uint16_t, T> decode(uint16_t encodedTag)
{
int type = 0;
uint16_t tag;
// simple linear search as there are only a few entries
for (auto it = begin(tagInfo); it != end(tagInfo); it++)
{
if (encodedTag >= it->start && encodedTag < it->last )
{
// tag is in the range
return {encodedTag - it->start , (T)type};
}
type++;
}
assert(false);
return {0,(T)0};
}
std::string getName(T tagType) {return(tagInfo[tagType].name);}
rdwrT getRdwr(T tagType) {return(tagInfo[tagType].rdwr);}
private:
std::vector<tagTypeInfo> tagInfo;
};
extern std::vector<tagTypeInfo> rdTag;
extern std::vector<tagTypeInfo> wrTag;
//using rdTagEncode = encodedTag<rdTagT>(rdTag) <-- error
The cpp file contains:
std::vector<tagTypeInfo> rdTag {
{0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD},
{0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD},
{0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD}
};
std::vector<tagTypeInfo> wrTag {
{0, 0, NUM_HOSTWRTAG, "HostWrTag", RDWR_WR},
{0, 0, NUM_SYSWRTAG, "SysWrTag", RDWR_WR},
{0, 0, NUM_GCWRTAG, "GCWrTag", RDWR_WR}
};
My goal is to be able to just declare an encoder in the code elsewhere with
rdTagEncode myEncode;
However I cant seem to figure out the right syntax to do this. Any suggestions?
Using a derived class was the best solution. Thanks for the suggestion #appleapple
class encodedRdTag : public encodedTag<rdTagTypeT>
{
public:
encodedRdTag() : encodedTag({
{0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD},
{0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD},
{0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD}
}) {};
};
class encodedWrTag : public encodedTag<wrTagTypeT>
{
public:
encodedWrTag() : encodedTag({
{0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD},
{0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD},
{0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD}
}) {};
};
For completeness, here is the "dispatch based on type" method which I mentioned in comment above.
NOTE: this code doesn't work in original question as the rdTag and wrTag are same type thus independent of the class template T, but according to your own answer this may be actually what happends.
#include <vector>
struct tagTypeInfo{};
struct rdTagTypeT{};
struct wrTagTypeT{};
std::vector<tagTypeInfo> get_default_info(rdTagTypeT); // return wrTag
std::vector<tagTypeInfo> get_default_info(wrTagTypeT); // return wdTag
template <typename T>
struct encodedTag
{
encodedTag():encodedTag(get_default_info(T{})){}
encodedTag(std::vector<tagTypeInfo> tagInfo) : tagInfo(tagInfo){};
std::vector<tagTypeInfo> tagInfo;
};
using encodedRdTag = encodedTag<rdTagTypeT>;
using encodedWrTag = encodedTag<wrTagTypeT>;
void foo(){
encodedRdTag rd;
encodedWrTag rw;
}
I am trying to initialize an std::unordered_map using the constructor that accepts data through an initialization list and the initial number of buckets.
For some reason, that constructor works if I put it in main, but has a syntax error when I put it in a class header.
Specifically, the header, called momo.h:
#pragma once
#include <unordered_map>
namespace std
{
template <>
struct hash<std::pair<uint16_t, uint16_t>>
{
std::size_t operator()(const std::pair<uint16_t, uint16_t>& k) const
{
return (std::hash<long>()((((long)k.first) << 16) + (long)k.second));
}
};
}
class test
{
std::unordered_map<std::pair<uint16_t, uint16_t>, uint16_t> m_Z(
{ /* Fails here: syntax error: missing ')' before '{' */
{std::pair{ 1, 2 }, 3},
{std::pair{ 4, 5 }, 6}
}, 128);
};
While if I remove the definition from the header into main thus:
#include "Momo.h"
int main()
{
test X;
std::unordered_map<std::pair<uint16_t, uint16_t>, uint16_t> Y(
{
{std::pair{ 1, 2 }, 3},
{std::pair{ 4, 5 }, 6}
}, 128);
}
The code compiles without error. Why?
You need to braced-init-list(or uniform-initiation) the std::unordered_map in the class.
class test
{
std::unordered_map<std::pair<uint16_t, uint16_t>, uint16_t> m_Z{ // >> brased init
{
{std::pair{ 1, 2 }, 3},
{std::pair{ 4, 5 }, 6}
}, 128
}; // >>>
};
Templates generally are inline - you have to supply the definition with the declaration.
Global (static) data requires that there be exactly one definition of the data (but it can be declared multiple times).
So, for a class with static data, one normally declares the static in the class definition (header), and the storage as static in the implementation file (.cpp).
But what does one do for a template that needs to refer to static / global data?
Here's a bit of code to give you something somewhat concrete to consider:
// we represent in a formal manner anything that can be encoded in a MSVS format specification
// A format specification, which consists of optional and required fields, has the following form:
// %[flags][width][.precision][{h | l | ll | w | I | I32 | I64}] type
// based on https://msdn.microsoft.com/en-us/library/56e442dc.aspx
struct FormatSpec
{
enum Size {
normal,
h,
l,
ll,
w,
I,
I32,
I64
};
enum Type {
invalid,
character,
signed_integer,
unsigned_integer,
unsigned_octal,
unsigned_hex,
floating_point,
expontential_floating_point,
engineering_floating_point,
hex_double_floating_point,
pointer,
string,
z_string
};
unsigned fLeftAlign : 1;
unsigned fAlwaysSigned : 1;
unsigned fLeadingZeros : 1;
unsigned fBlankPadding : 1;
unsigned fBasePrefix : 1;
unsigned width;
unsigned precision;
Size size_;
Type type_;
};
struct FormatSpecTypeDatum
{
FormatSpec::Type id; // id
const TCHAR * symbol; // text symbol
};
FormatSpecTypeDatum kTypeSpecs[] =
{
{ FormatSpec::character, _T("c") },
{ FormatSpec::character, _T("C") },
{ FormatSpec::signed_integer, _T("d") },
{ FormatSpec::signed_integer, _T("i") },
{ FormatSpec::unsigned_octal, _T("o") },
{ FormatSpec::unsigned_integer, _T("u") },
{ FormatSpec::unsigned_hex, _T("x") },
{ FormatSpec::unsigned_hex, _T("X") },
{ FormatSpec::expontential_floating_point, _T("e") },
{ FormatSpec::expontential_floating_point, _T("E") },
{ FormatSpec::floating_point, _T("f") },
{ FormatSpec::floating_point, _T("F") },
{ FormatSpec::engineering_floating_point, _T("g") },
{ FormatSpec::engineering_floating_point, _T("G") },
{ FormatSpec::hex_double_floating_point, _T("a") },
{ FormatSpec::hex_double_floating_point, _T("A") },
{ FormatSpec::pointer, _T("p") },
{ FormatSpec::string, _T("s") },
{ FormatSpec::string, _T("S") },
{ FormatSpec::z_string, _T("Z") },
};
template <typename ctype>
bool DecodeFormatSpecType(const ctype * & format, FormatSpec & spec)
{
for (unsigned i = 0; i < countof(kTypeSpecs); ++i)
if (format[0] == kTypeSpecs[i].symbol[0])
{
spec.type_ = kTypeSpecs[i].id;
++format;
return true;
}
return false;
}
It's relatively simple - a symbolic ID to character representation lookup table.
I want to be able to use DecodeFormatSpecType<>() for char, unsigned char, wchar_t, etc.
I could remove the template from DecodeFormatSpecType() and just supply overloaded interfaces for various character types.
The main thing is that the data isn't really changing - an unsigned char 'c' and a wchar_t 'c' and a legacy char 'c' have the exact same value, regardless of the character's storage size (for core ASCII characters this is true, although there are undoubtedly some other encodings such as EDBIC where this isn't true, that's not the problem I'm attempting to solve here).
I just want to understand "how do I construct my C++ libraries so that I can access global data defined in exactly one location - which is stored as an array - and I want the accessing templated code to know the length of the global data, just like I can with normal non-templated code have a global symbol table like what I've shown in my example code by having the table and the implementation that needs its size both exist in the appropriate .cpp file"
Does that make sense?
global data + functions that need to know the exact definition but also can be presented (with an interface) this generic (to a valid domain).
A function template can use global functions and global data without any problem.
If you want to encapsulate the definition of kTypeSpecs and not have it defined in a header file, you can use couple of functions to provide access to the data.
size_t getNumberOfTypeSpecs();
// Provide read only access to the data.
FormatSpecTypeDatum const* getTypeSpecs();
and then implement DecodeFormatSpecType as
template <typename ctype>
bool DecodeFormatSpecType(const ctype * & format, FormatSpec & spec)
{
size_t num = getNumberOfTypeSpecs();
FormatSpecTypeDatum const* typeSpecs = getTypeSpecs();
for (unsigned i = 0; i < num; ++i)
if (format[0] == typeSpecs[i].symbol[0])
{
spec.type_ = typeSpecs[i].id;
++format;
return true;
}
return false;
}
The functions getNumberOfTypeSpecs and getTypeSpecs can be implemented in a .cpp file as:
// Make the data file scoped global variable.
static FormatSpecTypeDatum kTypeSpecs[] =
{
{ FormatSpec::character, _T("c") },
{ FormatSpec::character, _T("C") },
{ FormatSpec::signed_integer, _T("d") },
{ FormatSpec::signed_integer, _T("i") },
{ FormatSpec::unsigned_octal, _T("o") },
{ FormatSpec::unsigned_integer, _T("u") },
{ FormatSpec::unsigned_hex, _T("x") },
{ FormatSpec::unsigned_hex, _T("X") },
{ FormatSpec::expontential_floating_point, _T("e") },
{ FormatSpec::expontential_floating_point, _T("E") },
{ FormatSpec::floating_point, _T("f") },
{ FormatSpec::floating_point, _T("F") },
{ FormatSpec::engineering_floating_point, _T("g") },
{ FormatSpec::engineering_floating_point, _T("G") },
{ FormatSpec::hex_double_floating_point, _T("a") },
{ FormatSpec::hex_double_floating_point, _T("A") },
{ FormatSpec::pointer, _T("p") },
{ FormatSpec::string, _T("s") },
{ FormatSpec::string, _T("S") },
{ FormatSpec::z_string, _T("Z") },
};
size_t getNumberOfTypeSpecs()
{
return sizeof(kTypeSpecs)/sizeof(kTypeSpecs[0]);
}
FormatSpecTypeDatum const* getTypeSpecs()
{
return kTypeSpecs;
}
Update, in response to comment by OP
Yes, you can. The following are perfectly valid:
size_t getNumberOfTypeSpecs()
{
static constexpr size_t num = sizeof(kTypeSpecs)/sizeof(kTypeSpecs[0]);
return num;
}
constexpr size_t getNumberOfTypeSpecs()
{
return sizeof(kTypeSpecs)/sizeof(kTypeSpecs[0]);
}
I have a program which reads a 10 MByte file and processes the data as the data is being read in 4K chunks. The test usually takes 1 min - 2 min. But there are some instances when the program takes more than 10 min, at which point the test it killed and a core is generated. Following is the code that reads the file:
string filename("data.out");
ifstream ifs;
vector<char> buf(4096);
ifs.open(filename, ios::in | ios::binary);
if (!ifs.is_open()) {
cout << "ERROR : " << filename << "can't be opened." << endl;
VERIFY(ifs.is_open());
}
while (!ifs.eof()) {
ifs.read(buf.data(), buf.size()); <======== Line 1
process_data (buf.data(), ifs.gcount()); <======== Line 2
}
ifs.close();
I have two cores that show the program is stuck at Line 1 and Line 2.
Top of bt of core1 at Line 1:
#0 0x00007f942a462175 in std::istream::read (this=0x7fff4ce69de0,
__s=0x9120000 "\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324\324"..., __n=4096) at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/istream.tcc:651
Top of bt of core2 at Line 2:
#0 0x00000000004375f3 in std::__addressof<char> (__r=#0x7fa3176391a6: -128 '\200') at /usr/include/c++/4.7/bits/move.h:47
#1 0x0000000000436cd4 in std::vector<char, std::allocator<char> >::data (this=0x7fff346ad770)
at /usr/include/c++/4.7/bits/stl_vector.h:859
Initially, from core1, I thought the issue was with ifs.read() taking a long time. But after the second core, I am thinking the issue might be related to vector::data().
Is there a way I can tell if any part of the file has been read, by inspecting certain fields (e.g file offset) stored in ifstream.
I don't like posting dump of large structure, but here it is if someone can shed some light how I can figure out from this dump how much of the 10MB has been read.
(gdb) p ifs
$3 = warning: can't find linker symbol for virtual table for `std::basic_ifstream<char, std::char_traits<char> >' value
{
<std::basic_istream<char, std::char_traits<char> >> = {
<std::basic_ios<char, std::char_traits<char> >> = {
<std::ios_base> = {
_vptr.ios_base = 0xfbfcc0,
static boolalpha = std::_S_boolalpha,
static dec = std::_S_dec,
static fixed = std::_S_fixed,
static hex = std::_S_hex,
static internal = std::_S_internal,
static left = std::_S_left,
static oct = std::_S_oct,
static right = std::_S_right,
static scientific = std::_S_scientific,
static showbase = std::_S_showbase,
static showpoint = std::_S_showpoint,
static showpos = std::_S_showpos,
static skipws = std::_S_skipws,
static unitbuf = std::_S_unitbuf,
static uppercase = std::_S_uppercase,
static adjustfield = std::_S_adjustfield,
static basefield = std::_S_basefield,
static floatfield = std::_S_floatfield,
static badbit = std::_S_badbit,
static eofbit = std::_S_eofbit,
static failbit = std::_S_failbit,
static goodbit = std::_S_goodbit,
static app = std::_S_app,
static ate = std::_S_ate,
static binary = std::_S_bin,
static in = std::_S_in,
static out = std::_S_out,
static trunc = std::_S_trunc,
static beg = std::_S_beg,
static cur = std::_S_cur,
static end = std::_S_end,
_M_precision = 6,
_M_width = 0,
_M_flags = 4098,
_M_exception = std::_S_goodbit,
_M_streambuf_state = 5,
_M_callbacks = 0x0,
_M_word_zero = {
_M_pword = 0x0,
_M_iword = 0
},
_M_local_word = {{
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}, {
_M_pword = 0x0,
_M_iword = 0
}},
_M_word_size = 8,
_M_word = 0x7fff4ce69f20,
_M_ios_locale = {
static none = 0,
static ctype = 1,
static numeric = 2,
static collate = 4,
static time = 8,
static monetary = 16,
static messages = 32,
static all = 63,
_M_impl = 0x7f942a6e3aa0,
static _S_classic = 0x7f942a6e3aa0,
static _S_global = 0x7f942a6e3aa0,
static _S_categories = 0x7f942a6c86a0,
static _S_once = 2
}
},
members of std::basic_ios<char, std::char_traits<char> >:
_M_tie = 0x0,
_M_fill = 0 '\000',
_M_fill_init = false,
_M_streambuf = 0x7fff4ce69df0,
_M_ctype = 0x7f942a6e3d20,
_M_num_put = 0x7f942a6e4040,
_M_num_get = 0x7f942a6e4030
},
members of std::basic_istream<char, std::char_traits<char> >:
_vptr.basic_istream = 0xfbfc98,
_M_gcount = 0
},
members of std::basic_ifstream<char, std::char_traits<char> >:
_M_filebuf = warning: can't find linker symbol for virtual table for `std::basic_filebuf<char, std::char_traits<char> >' value
{
<std::basic_streambuf<char, std::char_traits<char> >> = {
_vptr.basic_streambuf = 0xfc0a70,
_M_in_beg = 0x6306000 "\317\317\317\......320\320\320\320"...,
_M_in_cur = 0x6307fff "",
_M_in_end = 0x6307fff "",
_M_out_beg = 0x0,
_M_out_cur = 0x0,
_M_out_end = 0x0,
_M_buf_locale = {
static none = 0,
static ctype = 1,
static numeric = 2,
static collate = 4,
static time = 8,
static monetary = 16,
static messages = 32,
static all = 63,
_M_impl = 0x7f942a6e3aa0,
static _S_classic = 0x7f942a6e3aa0,
static _S_global = 0x7f942a6e3aa0,
static _S_categories = 0x7f942a6c86a0,
static _S_once = 2
}
},
members of std::basic_filebuf<char, std::char_traits<char> >:
_M_lock = {
__data = {
__lock = 0,
__count = 0,
__owner = 0,
__nusers = 0,
__kind = 0,
__spins = 0,
__list = {
__prev = 0x0,
__next = 0x0
}
},
__size = '\000' <repeats 39 times>,
__align = 0
},
_M_file = {
_M_cfile = 0x70186c0,
_M_cfile_created = true
},
_M_mode = 12,
_M_state_beg = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
},
_M_state_cur = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
},
_M_state_last = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
},
_M_buf = 0x6306000 "\317\317\317\317\317\......320\320\320\320\320"...,
_M_buf_size = 8192,
_M_buf_allocated = true,
_M_reading = true,
_M_writing = false,
_M_pback = 0 '\000',
_M_pback_cur_save = 0x0,
_M_pback_end_save = 0x0,
_M_pback_init = false,
_M_codecvt = 0x7f942a6e3f60,
_M_ext_buf = 0x0,
_M_ext_buf_size = 0,
_M_ext_next = 0x0,
_M_ext_end = 0x0
}
}
(gdb)
Thank you,
Ahmed.
Do not loop on eof.
while (ifs.read(buf.data(), buf.size())) {
size_t read = ifs.gcount();
if(read==0) break; // don't trust passing `0` to `process_data`:
process_data(buf.data(), read);
if (read<buf.size()) break; // if we finished, end.
}
Finding the end of input is best done by attempting io, and noticing something went wrong. In this case, we read, count how many bytes we read, and when we read 0 bytes or have read fewer bytes than we expected to read, we decide there isn't any more data to come.
We also end if any failbit has been set on ifs by the IO operation.
I'm not that good in English, that's why my Question is probably wrong. But I have a problem and I don't know how to solve it or if it's even possible to do.
I have 2 Structs defined:
typedef struct
{
UINT16 ScriptNumber;
std::string ScriptText;
} StepStruct;
typedef struct
{
std::string SequenceName;
std::string DisplayName;
StepStruct SequenceSteps;
} SequenceStruct;
As you can see, the first Struct is a Member of the second struct. So I want both structs to by dynamical. So I created 2 Dynamic Arrays from the Type StepStruct and 1 dynamic Array from the Type SequenceStruct.
The two dynamical Arrays for of the Type StepStructs are defined as follows:
StepStruct gsFirstSkript[] =
{
{ 1 , "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
StepStruct gsSecondSkript[] =
{
{ 48, "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
Those to Structs are of the Type StepStruct. Now I want to do the Same with a SequenceStruct Type, but I want to assign the two Arrays I already have to it under the Struct Member SequenceSteps. I mean this as follows:
SequenceStruct gsSequenceList[] =
{
{ "FirstScript", "Test One", gsFirstSkript},
{ "SecondScript", "Test Two", gsSecondSkript}
}
If I now want to Read the Member gsSequenceList, I can not access any information under the SequenceSteps Index of it! What means, that the Data is not copied! I tried it with Pointers
but had no success.
UINT16 lTestVal = gsSequenceList[0].SequenceSteps[2].ScriptNumber;
So Can I mangage that this works, and lTestVal contains the Value 45?
typedef struct
{
std::string SequenceName;
std::string DisplayName;
StepStruct* SequenceSteps;
} SequenceStruct;
This will allow the code to compile and the test fragment you've shown will work.
However this will not copy the data. If you change gsFristSkript it will change in gsSequenceList as well. If you want to make a copy of the data you can either do that explicitly, have a constructor or just use vector<>.
Here's the solution with vector:
#include <vector>
...
typedef struct{
std::string SequenceName;
std::string DisplayName;
vector<StepStruct> SequenceSteps;
} SequenceStruct;
vector<StepStruct> gsFirstSkript =
{
{ 1 , "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
vector<StepStruct> gsSecondSkript =
{
{ 48, "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
SequenceStruct gsSequenceList[] =
{
{ "FirstScript", "Test One", gsFirstSkript},
{ "SecondScript", "Test Two", gsSecondSkript}
}