I am required to create a data structure and I have so far created a simple table consisting of 4 different vectors that represent variable. variable type, bool result and PKB output. I know that it is not the best way to do it but I was planning to insert and retrieve using index. However, I encounter a problem with Query ID because I am expecting to use getMethods to retrieve the information. I need to find a way to retrieve the information much more smoothly than to run through by index. The retrieval process will be by batch of Query ID.
I am new to Cplusplus and I am not sure what data structure or how I can solve it. I am not expecting a direct answer but a suggestion would suffice. Names that I probably never heard before. It would be best if you have a step by step guide.
---Query ID ---- Variable --- Variable Type --- bool result---- PKB output
---- 1 ------------------- x ----- assignment ----------- true ----------- null
------------------------------------------------- 1 ------------------- w ---------- while -------------- false ---------- null
------------------------------------------------- 1 ------------------ ifstat----------- if ------------- ----false ---- ----- null
------------------------------------------------ 2 ------------------- x ------ assignment ----------- false ---------- null --------------------------------------------
From what I understand reading your question, You can use a std::multimap using int and struct. For instance
// C++11 for nullptr
#include <string>
#include <map>
struct Data {
std::string variable;
std::string variableType;
bool result;
PKB output; // I suppose PKB is an already defined type
Data(std::string var, std::string varType, bool res = false, PKB out = nullptr) :
variable(var), variableType(varType), result(res), output(out) {}
inline bool operator <(const Data & rhs) {
. . . // Add your own comparison logic
}
};
std::multimap<int, Data> myMap;
myMap.insert((1, Data("x", "assignment", true)));
myMap.insert((1, Data("w", "while")));
myMap.insert((1, Data("ifstat", "if")));
myMap.insert((2, Data("x", "assignment")));
I don't think I understand the question completely. But I think your using the standard library that contains the def of a vector, meaning you would have to use the getters and setters of that std. I would just make a function with a quick search algorithm that uses the getter already defined in the vector.
Related
In a C++ program I am trying to set a custom comparison function for a Berkeley DB, using the Db::set_bt_function member function (the DB is opened as a BTREE type). My code works fine when I'm not changing the comparison function; I can put and get keys/values using Db::put and Db::get.
To try the set_bt_function method, I defined my own "lexicographic comparison" as follows:
int compkeys(Db *db, const Dbt *dbt1, const Dbt *dbt2, size_t *locp) {
size_t s = dbt1->get_size() > dbt2->get_size() ? dbt2->get_size() : dbt1->get_size();
int c = std::memcmp(dbt1->get_data(), dbt2->get_data(), s);
if(c != 0) return c;
if(dbt1->get_size() < dbt2->get_size()) return -1;
if(dbt1->get_size() > dbt2->get_size()) return 1;
return 0;
}
So this should lead to exactly the same behavior as my reference code, when the comparison function isn't changed, since by default Berkeley DB uses lexicographical order.
Yet, when using this comparison function, Db::get doesn't work anymore. It returns -30999 (DB_BUFFER_SMALL).
Here is what I am doing to get the value associated with a given key:
Db* _dbm = ... /* DB is open */
std::vector<char> mykey;
... /* mykey is set to some content */
Dbt db_key((void*)(mykey.data()), uint32_t(mykey.size()));
Dbt db_data;
db_key.set_flags(DB_DBT_USERMEM);
db_data.set_flags(DB_DBT_MALLOC);
int status = _dbm->get(NULL, &db_key, &db_data, 0);
... /* check status, do something with db_data */
free(db_data.get_data());
Any idea why this code works when I'm not setting the comparison function, and doesn't when I am?
Note: if I access key/values using a cursor (Dbc::get) I don't have this issue.
The DB_BUFFER_SMALL error in this case is complaining about your db_key Dbt. You need to call db_key.set_ulen(uint32_t(mykey.size())) to tell BDB how much space you've allocated to hold the keys that come out of the database.
Things get a little weirder when you're using a custom comparison function. You can have data in the key that's not part of the compare - and not in the key that you passed in to get(). For this reason, BDB returns the key it found in the database in your db_key.
When setting the ulen, make it large enough to hold any key that can come back from the database. You may find that it's saner to just keep a char array on the stack to deal with this key in/out behavior.
Currently I am looking at a file which has information in this format:
header:
seq: 313
stamp:
secs: 1488279773
nsecs: 788520137
frame_id: ardrone_base_link
batteryPercent: 58.0
state: 2
magX: 74
magY: -32
magZ: 42
pressure: 90927
temp: 427
wind_speed: 0.0
wind_angle: 0.0
wind_comp_angle: 0.0
rotX: 1.34500002861
rotY: -2.72399997711
rotZ: -4.82999992371
altd: 0
vx: -1.59770445708e-40
vy: -3.68179961114e-40
vz: -0.0
ax: 0.0632314383984
ay: 0.0111897774041
az: 0.982218265533
motor1: 0
motor2: 0
motor3: 0
motor4: 0
tags_count: 0
tags_type: []
tags_xc: []
tags_yc: []
tags_width: []
tags_height: []
tags_orientation: []
tags_distance: []
tm: 590774784.0
Now as you can see, there are multiple sections, with the header seq clearly being an identifier here that can possibly be used in an stl::multimap. However as you can see, I want all the information to be stored, including a way to understand that secs is a subsection of stamp which in turn is a subsection of header. Also, the information I get would vary a fair bit, so I cannot make a struct which would handle this information.
How would I go about this?
Yes. It looks like YAML. For sure.
If you need a private object - you can create something like that:
enum objType {
OBJ_STRING,
OBJ_VECTOR,
OBJ_MAP
}
class DataObj {
public:
DataObj(const string&, const string&); // Creates object with single name-value data
DataObj(DataObj *); // Creates object of vector type
DataObj(const string&, DataObj *); // Created object of map type
void setObjectKey(const string&);
void setObjectType(objType);
void addObject(DataObj *);
...
private:
objType e_type;
string objData;
string objKey;
vector<DataObj *> objVector;
map<string,DataObj*> objMap;
}
So, you can always change data object from string to vector and then - to map upon file parsing. And then recursively get data until you reach single level string object data.
As Biffen commented, you could use a YAML library for this.
If you are looking for a generic way of storing information like this (different data types, nested data, etc), you can either use inheritance to model different types (numbers, strings, or containers of of other data), or use tagged unions that either store a value or a container to more values.
An example of the latter is implemented in https://github.com/nlohmann/json
You could adapt this technique to your needs.
Good morning, I'm stuck using a map in the correct way.
Situation
A database table with unique ID and two other codes
ID (long) | Type (long) | Name (string)
to fill the map correctly I've defined it in this way:
map<long, MyObject>
where key is my ID and the object holds all the stuff. The map works correctly, I load all rows and I navigate easily inside of it.
Troubles
Troubles come when I need to sort the rows using a criteria which is not the key but:
Type
Name
Looking around the Internet I found that I should:
Define the operator< for MyObject or...
Define another type of comparator for my map.
I did the step 1., but with no success (it is never called). I'm trying to do the point 2. but with even less success.
I'll paste some code to help:
class CSitoWebRigaVariante
{
public:
bool m_bSriDelete;
bool m_bSriVisibile;
long m_lSriId;
long m_lSriIdTipol;
long m_lSriCodGes;
CString m_strSriCodMat;
public:
CSitoWebRigaVariante(void);
CSitoWebRigaVariante(const CSitoWebRigaVariante& cRiga);
~CSitoWebRigaVariante(void);
bool operator<(const CSitoWebRigaVariante& cRiga);
void operator=(const CSitoWebRigaVariante& cRiga);
void Azzera(void);
static void CaricaDaMDB(CDB* pDB, long lIdVM, map<long, CSitoWebRigaVariante>& cRighe);
};
typedef map<long, CSitoWebRigaVariante> CSWRighe;
///> Static method to fill a map.
void CSitoWebRigaVariante::CaricaDaMDB(CADODatabase* pDB, long lIdVM, map<long, CSitoWebRigaVariante>& cRighe)
{
BOOL bValRit;
CRecordset* pRS;
CSitoWebRigaVariante riga;
CString strInt;
pRS = new CADORecordset(pDB);
strInt.Format(_T("SELECT * FROM SITOWEB_RIVARMAT WHERE sri_idvarmat = %ld;"), lIdVM);
cRighe.clear();
if (pRS->Open(strInt, CADORecordset::openQuery) == TRUE && pRS->GetRecordCount() > 0)
{
while (pRS->IsEOF() == FALSE)
{
bValRit = pRS->GetFieldValue(_T("sri_id"), riga.m_lSriId);
bValRit &= pRS->GetFieldValue(_T("sri_idtipol"), riga.m_lSriIdTipol);
bValRit &= pRS->GetFieldValue(_T("sri_codges"), riga.m_lSriCodGes);
bValRit &= pRS->GetFieldValue(_T("sri_codmat"), riga.m_strSriCodMat);
bValRit &= pRS->GetFieldValue(_T("sri_delete"), riga.m_bSriDelete);
bValRit &= pRS->GetFieldValue(_T("sri_visibile"), riga.m_bSriVisibile);
cRighe.insert(pair<long, CSitoWebRigaVariante>(riga.m_lSriCodGes, riga));
pRS->MoveNext();
}
}
pRS->Close();
delete pRS;
}
I'm using Visual Studio 2010, MFC.
Any help is appreciated.
std::map is not a multi-index associative container. Its find method (and other things) uses the key as a search criteria. There's no possibility to specify another search criteria. It's why it's a "single-index lookup table".
You can use Boost.MultiIndex. It was designed for your case and supports multiple indexes (as the name suggests), both unique and not-unique.
Or you can use multiple map instances with different keys. If keys are not unique you need std::multimap.
I would recommend you to use map for model (for storing data). When you need to display information, you can just output it in the order you need it to be shown. Sorting must be done not at level of storing items, but at level of displaying them.
Although, in each situation you will need to do reordering only once.
Also, if any help is appreciated, I would strongly recommend you to do a
typedef long MyId;
and to use VS 2015.
The map class provides a Compare parameter of the constructor. You could not complete your target by setting Compare as map has only support key compare function.
The first idea of mine is construct a class support your tables schema.
class Example
{
public:
<your code>
void sortByID();
void sortByType();
void sortByName();
private:
long ID_;
long Type_;
string Name_;
};
But it sounds terrible. As once your table change, you should hard copy.So why you just get result using database order by?
I am in the process of porting a PHP console app to C++, to learn more about C++ and reignite my old love for the language.
One of the things I need is traversing through a parsed YAML tree, to get an item by it's path. I am currently only handling string keys and YAML map types, just to keep it simple.
Here's the test I wrote using Catch to identify my issue:
#define CATCH_CONFIG_MAIN
#include <yaml-cpp/yaml.h>
#include <boost/foreach.hpp>
#include "include/catch.hpp"
// In my actual implementation, this function is a method
// of a class, and 'config' is a class member
// but the semantics and types are the same
YAML::Node lookup(YAML::Node config, std::vector<std::string>& path) {
YAML::Node ptr = config;
BOOST_FOREACH(std::string element, path)
{
ptr = ptr[element];
}
return ptr;
}
TEST_CASE ("Loading YAML data", "[loader]") {
const char *str_config =
"key:\n"
" child: Hello world\n"
;
YAML::Node config = YAML::Load(str_config);
std::vector<std::string> path;
path.push_back("key");
path.push_back("child");
// the first one succeeds:
REQUIRE( lookup(config, path).IsDefined() );
// but the second one fails.
REQUIRE( lookup(config, path).IsDefined() );
}
Now if I run this test, it fails with the following message:
-------------------------------------------------------------------------------
Loading YAML data
-------------------------------------------------------------------------------
/home/gerard/work/z-cpp/test.cpp:26
...............................................................................
/home/gerard/work/z-cpp/test.cpp:42: FAILED:
REQUIRE( lookup(config, path).IsDefined() )
with expansion:
false
===============================================================================
test cases: 1 | 1 failed
assertions: 2 | 1 passed | 1 failed
I have isolated that if I clone the node in the lookup method like this:
YAML::Node ptr = YAML::Clone(config);
it works just fine.
What it does
Somehow, the internal state of the 'config' object is altered. But since I declare my local variable not as a reference, I expected it to make a copy of the original. I started out using just references, with which I ran into the same issue.
Also, if the vector is initialized separately a second time with another instance, it acts the same (erroneous) way, so it's not the vector's fault ;)
I have dived a bit into the source code of yaml-cpp and tried to figure out if I am missing some obvious pointers (pun intended) or API misuse, but I can't figure it out...
What it should do
As my 'lookup' is just a read operation, I would like to have as much things const as possible, and not have the original object's state altered. Also, cloning the entire tree will make it very expensive as I plan to do a lot of these lookups in the entire application...
What am I overlooking here?
In yaml-cpp, nodes are reference types, so operator= actually changes their internals.
This often is what you want, but your example shows that in some cases it produces really counterintuitive behavior.
I agree this is weird. I've filed an issue to think about how to prevent this in intuitive behavior.
To work around this, in your example, you could switch to recursion:
template <typename Iter>
YAML::Node lookup(YAML::Node node, Iter start, Iter end) {
if (start == end) {
return node;
}
return lookup(node[*start], next(start), end);
}
...
vector<string> path = ...
YAML::Node value = lookup(config, path.begin(), path.end());
I am new to Threading Building Blocks (TBB); I would need to implement the following logic with TBB nodes:
A node of type N receives two inputs; for instance:
1. std::vector // data
2. bool // flag
These inputs come asynchronously.
If the input is of type 1, process the data owned by the node of type N to produce two outputs, for instance:
a. std::vector
b. int
If the input is of type 2, process the data owned by the node of type N to produce one output, say a std::vector.
I have been trying to formulate the input part using a tbb::flow::or_node, and the output part using tbb::flow::multifunction_node.
If there is only one input and multiple outputs, this logic can be written with tbb::flow::multifunction_node (I tested, it works). If there is one output, and multiple inputs, I found example of code illustrating solutions. However, it is not clear to me how the case of multiple asynchronous inputs and multiple outputs can be implemented with the TBB framework. Suggestions welcome.
You should be able to do what you want with the current implementation of or_node. (We are re-designing the output of the or_node to make it more friendly, but we need input from users like you on issues with the or_node Community Preview Feature.)
One thing to remember is to turn on the CPF when you are compiling code with the or_node. The switch is -DTBB_PREVIEW_GRAPH_NODES=1 .
# define TBB_PREVIEW_GRAPH_NODES 1 // necessary to turn on the or_node community Preview Feature.
#include "tbb/flow_graph.h"
#include <vector>
using namespace tbb::flow;
// The output format of the or_node is a struct that contains
// 1. the index of the input that the message appeared on, and
// 2. a tuple, the (i-1)th element of which is the message received
typedef or_node<tuple<std::vector<double>, bool> > my_or_node_type;
// it wasn't clear from the description if you wanted to differentiate between the vectors output with
// an input of type 1. or type 2. If you need to do that you can add an extra output port to the multifunction_node.
typedef multifunction_node<my_or_node_type::output_type, tuple<std::vector<double>, int> > my_mf_node_type;
struct mf_node_body {
void operator()(const my_or_node_type::output_type &in, my_mf_node_type::output_ports_type &op) {
switch(in.indx) {
case 0: {
// do the operation for the first input (the std::vector) The vector will be in
// get<0>(in.result). Remember you are copying vectors here, so if you have big
// vectors you will probably want to do some buffer management on your own and
// pass refs to the vector instead.
}
break;
case 1: {
// do the operation signaled by the second input (the bool.) The value of the
// input is in get<1>(in.result).
}
break;
}
}
};
main() {
graph g;
my_or_node_type multi_in(g);
my_mf_node_type multi_out(g, unlimited, mf_node_body());
// if the vector-producing node is called vpn, you attach it to the 0-th input of the or_node with
// make_edge(vpn, input_port<0>(multi_in));
//
// the bool-producing node bn can be attached similarly:
// make_edge(bn, input_port<1>(multi_in);
//
// attach the multi-in to the multi-out:
// make_edge(multi_in, multi_out);
//
// attach the vector consumer node vcn
// make_edge(output_port<0>(multi_out), vcn);
//
// attach the integer output to the int consuming node icn
// make_edge(output_port<1>(multi_out), icn);
//
// start up the graph and make sure to do a wait_for_all() at the end.
}
Remember that the multifunction_node body is invoked in parallel, so the work it does should not have race conditions (unless you want race conditions for some reason.) You can make the node body execute serially by constructing it with serial instead of unlimited. And the only way to ensure you can safely destroy the graph is to make sure no tasks are executing any of the nodes. The best way to do this is to do a g.wait_for_all().
Regards,
Chris
P.S. - one addendum. If the multifunction_node is defined serial, it will have an input buffer unless you explicitly exclude it. This may change the behavior of your graph if you are not expecting the buffer to be there.