Can't call bsoncxx::document::value::view() - mongodb

I'd like to look at the results of retrieving a single document from a MongoDB using the C++ 3.0 driver. The driver documentation describes the view() method of the bsoncxx::document::value class (which is returned by mongocxx::collection::find_one). When I attempt to use it like this:
#include <bsoncxx/document/view.hpp>
#include <bsoncxx/document/value.hpp>
#include <mongocxx/instance>
#include <mongocxx/client>
mongocxx::instance inst{};
mongocxx::client conn{};
bsoncxx::document::view doc;
auto db = conn["test"];
try {
auto docObj = db["collection"].find_one(document{} <<
"field" << "value" << finalize);
doc = docObj.view();
} catch (mongocxx::exception::query e) {
std::cerr << "Couldn't retrieve document";
return NULL;
}
...
I get the following compilation error:
error: 'struct core::v1::optional<bsoncxx::v0::document::value>' has no member named 'view'
at the line
doc = docObj.view();
What am I doing wrong? If this is not the the correct idiom for using find_one(), what should I be using instead?

Found it. The bsoncxx::optional template means that the members of bsoncxx::document::value are available as var->member. The above code should have read:
doc = docObj->view();
It was confusing because docObj is an object, not a pointer, but an object that presents its underlying object as though it were a pointer.

core::v1::optional<T> acts much like std::experimental::optional<T>.
And as described in documentation for std::experimental::optional (or, since c++17, std::optional),
When an object of type optional is contextually converted to bool, the conversion returns true if the object contains a value and false if it does not contain a value.
you have to check your docObj for containing a value by applying operator bool to it because
The behavior [of operator*] is undefined if *this does not contain a value
(there is described some bad_optional_access exception, but documentation for operator* says that trying to access contained value when there is no value leads to UB)
So, your code has to look like
if(docObj) {
doc docObj->view();
} else {
//Throw an exception? log an error to console?
//Do nothing?
std::cerr << "find_one() failed for" << std::endl <<
bsoncxx::to_json(
document{} << "field" << "value" << finalize
) << std::endl;
}
This may help if find_one() failed for some reason.
Yes, implementations of core::v1::optional<T> and std::optional may differ (at least I can't find it at official api documentation).
But it's better to check.
UPD: As shown in file for stdx::optional, I'm (partially?) right: it can use std::experimental::optional

Related

Failed trying yo parse Kitchen time with date.h or chronos

I'm developing a C++ timestamp parser that could check if any given string can be a timestamp representation, covering various formats.
I've tested some libraries and finally, I'm using the single header one developed by #howard-hinnant.
The only problem is with the Kitchen format 03:04AM (HH:MM<AM|PM>).
This is the code that I'm using:
#include "date.h"
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::string const fmt = "%I:%M%p" ;
std::string const time;
std::string const name;
date::fields<std::chrono::nanoseconds> fds {};
std::chrono::minutes offset {};
std::string abbrev;
const std::string in = "3:04a.m.";
std::stringstream ss(in);
std::unordered_map<std::string, std::string> result;
date::from_stream(ss, fmt.c_str(), fds, &abbrev, &offset);
if (!ss.fail())
{
if (fds.has_tod && fds.tod.in_conventional_range())
{
std::cout << "result hour " << std::to_string(fds.tod.hours().count()) << std::endl;
std::cout << ". minutes " << std::to_string(fds.tod.minutes().count())<< std::endl;
std::cout << ". seconds " << std::to_string(fds.tod.seconds().count())<< std::endl;
}
}
else
{
std::cout << "failed" << std::endl;
}
}
What I'm doing wrong, the code works great with other formats? is there a chance that parsing a date requires more fields in order to process it fully (year, month, day)?
Hope I made myself clear, thanks in advance!
In the "C" locale, %p refers to one of AM or PM. You have "a.m.". Removing the '.' works for me.
There is one other caveat: The POSIX spec for strptime specifies that case should be ignored. And my date lib follows the POSIX spec on this. However by default this library forwards to your std::library for this functionality. And some implementations didn't get the memo on this. They may not accept lower case.
If this happens for you, you can work around this std::lib bug by compiling with -DONLY_C_LOCALE on the command line (or set ONLY_C_LOCALE=1 in your IDE wherever macros are set). This tells the date lib to do the %p parse itself, instead of forwarding to the std::lib. And it will correctly do a case-insensitive parse. However it assumes that the "C" locale is in effect.

Pre-compile textual replacement macro with arguments

I am trying to create some kind of a dut_error wrapper. Something that will take some arguments and construct them in a specific way to a dut_error.
I can't use a method to replace the calls to dut_error because to my understanding after check that ... then ... else can only come a dut_error (or dut_errorf). And indeed if I try to do something like:
my_dut_error(arg1: string, arg2: string) is {
dut_error("first argument is ", arg, " and second argument is ", arg2);
};
check that FALSE else my_dut_error("check1", "check2");
I get an error:
*** Error: Unrecognized exp
[Unrecognized expression 'FALSE else my_dut_error("check1", "check2")']
at line x in main.e
check that FALSE else my_dut_error("check1", "check2");
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So I thought about defining a macro to simply do a textual replace from my wrapper to an actual dut_error:
define <my_dut_error'exp> "my_dut_error(<arg1'name>, <arg2'name>)" as {
dut_error("first argument is ", <arg1'name>, " and second argument is ", <arg2'name>)
};
But got the same error.
Then I read about the preprocessor directive #define so tried:
#define my_dut_error(arg1, arg2) dut_error("first argument is ", arg, " and second argument is ", arg2)
But that just gave a syntax error.
How can I define a pre-compiled textual replacement macro that takes arguments, similar to C?
The reason I want to do that is to achieve some sort of an "interface" to the dut_error so all errors have a consistent structure. This way, different people writing different errors will only pass the arguments necessary by that interface and internally an appropriate message will be created.
not sure i understood what you want to do in the wrapper, but perhaps you can achieve what you want by using the dut_error_struct.
it has set of api, which you can use as hooks (do something when the error is caught) and to query about the specific error.
for example:
extend dut_error_struct {
pre_error() is also {
if source_method_name() == "post_generate" and
source_struct() is a BLUE packet {
out("\nProblem in generation? ", source_location());
// do something for error during generation
};
write() is first {
if get_mesage() ~ "AHB Error..." {
ahb_monitor::increase_errors();
};
};
};
dut_error accepts one parameter, one string. but you can decide of a "separator", that will define two parts to the message.
e.g. - instruct people to write "XXX" in the message, before "first arg" and "second arg".
check that legal else dut_error("ONE thing", "XXX", "another thing");
check that x < 7 else dut_error("failure ", "XXX", "of x not 7 but is ", x);
extend dut_error_struct {
write() is first {
var message_parts := str_split(get_message(), "XXX");
if message_parts.size() == 2 {
out ("First part of message is ", message_parts[0],
"\nand second part of message is ", message_parts[1]
);
};
};
I could get pretty close to what I want using the dut_errorf method combined with a preprocessor directive defining the format string:
#define DUT_FORMAT "first argument is %s and second argument is %s"
check that FALSE else dut_errorf(DUT_FORMAT, "check1", "check2");
but I would still prefer a way that doesn't require this DUT_FORMAT directive and instead uses dut_error_struct or something similar.

Creating a numpy python string array with pybind11

I am trying to modify a numpy string array from c++ with pybind11. The code i am using has the following structure:
py::array_t<py::str> process_array(py::array_t<py::str> input);
PYBIND11_EMBEDDED_MODULE(fast_calc, m) {
m.def("process_array", process_array);
}
py::array_t<py::str> process_array(py::array_t<py::str> input) {
auto buf = input.request();
cout << &buf;
return input;
}
The problem i face is this error message:
pybind11/numpy.h:1114:19: error: static assertion failed: Attempt to use a non-POD or unimplemented POD type as a numpy dtype
static_assert(is_pod_struct::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
Not sure whats the catch. In python you can create numpy string arrays so what am i doing wrong?
Thanks.
Fixed length strings are supported in pybind11 (tested on v2.2.3, CentOS7, python3.6.5) by using the pybind11::array_t< std::array<char, N> > or char[N] type. Likely you'll want to pad out the string with null values just in case, as the standard pitfalls of C-style strings apply (e.g. N-1 useable characters). I prefer working with std::array as it doesn't decay to a char* without calling .data() making your intentions clearer to other readers.
So some psuedocode would look like this for a vector of 16 byte strings:
using np_str_t = std::array<char, 16>;
pybind11::array_t<np_str_t> cstring_array(vector.size());
np_str_t* array_of_cstr_ptr = reinterpret_cast<np_str_t*>(cstring_array.request().ptr);
for(const auto & s : vector)
{
std::strncpy(array_of_cstr_ptr->data(), s.data(), array_of_cstr_ptr->size());
array_of_cstr_ptr++;
}
return cstring_array; //numpy array back to python code
And then in python:
array([b'ABC', b'XYZ'], dtype='|S16')

Why isn't my LLVM alias analysis pass being called?

I'm attempting to do some alias analysis & other memory inspection. I've written a pointless AliasAnalysis pass (that says everything must alias) to attempt to verify that my pass is getting picked up & run by opt.
I run opt with: opt -load ~/Applications/llvm/lib/MustAA.so -must-aa -aa-eval -debug < trace0.ll -debug-pass=Structure
I see my pass being initialized, but never being called (I see only may alias results).
Any ideas as to what to do to debug this? Or what I'm missing? I've read through http://llvm.org/docs/AliasAnalysis.html and don't see anything that I'm missing.
Here's the full source code of my pass:
#define DEBUG_TYPE "must-aa"
#include "llvm/Pass.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
namespace {
struct EverythingMustAlias : public ImmutablePass, public AliasAnalysis {
static char ID;
EverythingMustAlias() : ImmutablePass(ID) {}
virtual void *getAdjustedAnalysisPointer(AnalysisID ID) {
errs() << "called getAdjustedAnalysisPointer with " << ID << "\n";
if (ID == &AliasAnalysis::ID)
return (AliasAnalysis*)this;
return this;
}
virtual void initializePass() {
DEBUG(dbgs() << "Initializing everything-must-alias\n");
InitializeAliasAnalysis(this);
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AliasAnalysis::getAnalysisUsage(AU);
AU.setPreservesAll();
}
virtual AliasResult alias(const Location &LocA, const Location &LocB) {
DEBUG(dbgs() << "Everything must alias!\n");
return AliasAnalysis::MustAlias;
}
};
}
namespace llvm {
void initializeEverythingMustAliasPass(PassRegistry &Registry);
}
char EverythingMustAlias::ID = 0;
static RegisterPass<EverythingMustAlias> A("must-aa", "Everything must alias");
INITIALIZE_AG_PASS(EverythingMustAlias, AliasAnalysis, "must-aa",
"Everything must alias", false, true, false)
Running opt as above produces:
Args: opt -load /home/moconnor/Applications/llvm/lib/MustAA.so -must-aa -aa-eval -debug -debug-pass=Structure
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.
Subtarget features: SSELevel 8, 3DNowLevel 0, 64bit 1
Initializing everything-must-alias
Pass Arguments: -targetlibinfo -datalayout -notti -basictti -x86tti -no-aa -must-aa -aa-eval -preverify -domtree -verify
Target Library Information
Data Layout
No target information
Target independent code generator's TTI
X86 Target Transform Info
No Alias Analysis (always returns 'may' alias)
Everything must alias
ModulePass Manager
FunctionPass Manager
Exhaustive Alias Analysis Precision Evaluator
Preliminary module verification
Dominator Tree Construction
Module Verifier
===== Alias Analysis Evaluator Report =====
163 Total Alias Queries Performed
0 no alias responses (0.0%)
163 may alias responses (100.0%)
0 partial alias responses (0.0%)
0 must alias responses (0.0%)
Alias Analysis Evaluator Pointer Alias Summary: 0%/100%/0%/0%
168 Total ModRef Queries Performed
0 no mod/ref responses (0.0%)
0 mod responses (0.0%)
0 ref responses (0.0%)
168 mod & ref responses (100.0%)
Alias Analysis Evaluator Mod/Ref Summary: 0%/0%/0%/100%
Note the 163 may alias responses when my pass is returning MustAlias.
Edit: On a suggestion on the mailing list, I added the following member function since my pass uses multiple inheritance. It doesn't seem to change anything or get called.
virtual void *getAdjustedAnalysisPointer(AnalysisID ID) {
errs() << "called getAdjustedAnalysisPointer with " << ID << "\n";
if (ID == &AliasAnalysis::ID)
return (AliasAnalysis*)this;
return this;
}
I changed:
static RegisterPass<EverythingMustAlias> A("must-aa", "Everything must alias");
INITIALIZE_AG_PASS(EverythingMustAlias, AliasAnalysis, "must-aa",
"Everything must alias", false, true, false)
to
static RegisterPass<EverythingMustAlias> X("must-aa", "Everything must alias", false, true);
static RegisterAnalysisGroup<AliasAnalysis> Y(X);
Apparently INITIALIZE_AG_PASS only defines the registration function & so is only useful for a pass that is statically linked into an LLVM executable (or something). RegisterAnalysisGroup is run when this module is dynamically linked in so it is then registered.

Retrieving gdcm DataElement values as strings

I am basically trying to read out all or most attribute values from a DICOM file, using the gdcm C++ library. I am having hard time to get out any non-string values. The gdcm examples generally assume I know the group/element numbers beforehand so I can use the Attribute template classes, but I have no need or interest in them, I just have to report all attribute names and values. Actually the values should go into an XML so I need a string representation. What I currently have is something like:
for (gdcm::DataSet::ConstIterator it = ds.Begin(); it!=ds.End(); ++it) {
const gdcm::DataElement& elem = *it;
if (elem.GetVR() != gdcm::VR::SQ) {
const gdcm::Tag& tag = elem.GetTag();
std::cout << dict.GetDictEntry(tag).GetKeyword() << ": ";
std::cout << elem.GetValue() << "\n";
}
}
It seems for numeric values like UL the output is something like "Loaded:4", presumably meaning that the library has loaded 4 bytes of data (an unsigned long). This is not helpful at all, how to get the actual value? I must be certainly overlooking something obvious.
From the examples it seems there is a gdcm::StringFilter class which is able to do that, but it seems it wants to search each element by itself in the DICOM file, which would make the algorithm complexity quadratic, this is certainly something I would like to avoid.
TIA
Paavo
Have you looked at gdcmdump? You can use it to output the DICOM file as text or XML. You can also look at the source to see how it does this.
I ended up with extracting parts of gdcm::StringFilter::ToStringPair() into a separate function. Seems to work well for simpler DCM files at least...
You could also start by reading the FAQ, in particular How do I convert an attribute value to a string ?
As explained there, you simply need to use gdcm::StringFilter:
sf = gdcm.StringFilter()
sf.SetFile(r.GetFile())
print sf.ToStringPair(gdcm.Tag(0x0028,0x0010))
Try something like this:
gdcm::Reader reader;
reader.SetFileName( absSlicePath.c_str() );
if( !_reader.Read() )
{
return;
}
gdcm::File file = reader.GetFile();
gdcm::DataSet ds = file.GetDataSet();
std::stringstream strm;
strm << ds;
you get a stringstream containing all the DICOM tags-values.
Actually, most of the DICOM classes (DataElement, DataSet, etc) have the std::ostream & operator<< (std::ostream &_os, const *Some_Class* &_val) overloaded. So you can just expand the for loop and use operator<< to put the values into the stringstream, and then into the string.
For example, if you are using QT :
ui->pTagsTxt->append(QString(strm.str().c_str()));