I need to fill pdf form.
To do this I found and use qPDF c++ library.
I added libqpdf.dll.a on fillPdf.pro using :
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll
INCLUDEPATH += $$PWD/qpdf
DEPENDPATH += $$PWD/qpdf
I also added all includes .h and .hh headers from qpdf library to my project.
But I still have bugs that look like linkage problems :
.o:-1: In function `ZN8reporter8fillTestEPKcS1_S1_':
.cpp:19: erreur : undefined reference to `QPDF::QPDF()'
.cpp:20: erreur : undefined reference to `QPDF::processFile(char const*, char const*)' ^
.cpp:19: erreur : undefined reference to `QPDF::~QPDF()'
collect2.exe:-1: erreur : error: ld returned 1 exit status
summarised code all symbols are recognised by qt creator and i have access to theire classes by clicking on them :
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
#include <iostream>
int main(int argc, char* argv[])
{
char* whoami = QUtil::getWhoami(argv[0]);
if (argc != 3)
{
std::cerr << "Usage: " << whoami << " infile outfile" << std::endl;
return 2;
}
char const* infile = argv[1];
char const* outfile = argv[2];
QPDF in;
in.processFile(infile);
int pageno = 0;
std::vector<QPDFObjectHandle> const& pages = in.getAllPages();
for (std::vector<QPDFObjectHandle>::const_iterator iter = pages.begin();
iter != pages.end(); ++iter)
{
std::cout << ++pageno << " ";
QPDFObjectHandle page = *iter;
page.replaceKey(
"/Contents",
QPDFObjectHandle::newStream(&in, "q Q"));
}
QPDFWriter out(in, outfile);
out.write();
return 0;
}
More information :
QPDF WINDOWS Lib : https://sourceforge.net/projects/qpdf/files/qpdf/8.4.0/
includes : https://github.com/qpdf/qpdf/tree/master/include/qpdf
exemple : https://github.com/qpdf/qpdf/blob/master/examples/pdf-set-form-values.cc
I am using qt creator 4.4.0 based on qt 5.9.1 (MSVC 2015, 32bit)
Can someone tell me where am i wrong?
My .pro
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG += qt
QT += core gui
QT += axcontainer
QT += serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
SOURCES += main.cpp
HEADERS += \
qpdf/Buffer.hh \
qpdf/BufferInputSource.hh \
qpdf/ClosedFileInputSource.hh \
qpdf/Constants.h \
qpdf/DLL.h \
qpdf/FileInputSource.hh \
qpdf/InputSource.hh \
qpdf/JSON.hh \
qpdf/Pipeline.hh \
qpdf/Pl_Buffer.hh \
qpdf/Pl_Concatenate.hh \
qpdf/Pl_Count.hh \
qpdf/Pl_DCT.hh \
qpdf/Pl_Discard.hh \
qpdf/Pl_Flate.hh \
qpdf/Pl_QPDFTokenizer.hh \
qpdf/Pl_RunLength.hh \
qpdf/Pl_StdioFile.hh \
qpdf/PointerHolder.hh \
qpdf/qpdf-c.h \
qpdf/QPDF.hh \
qpdf/QPDFAcroFormDocumentHelper.hh \
qpdf/QPDFAnnotationObjectHelper.hh \
qpdf/QPDFDocumentHelper.hh \
qpdf/QPDFExc.hh \
qpdf/QPDFFormFieldObjectHelper.hh \
qpdf/QPDFNameTreeObjectHelper.hh \
qpdf/QPDFNumberTreeObjectHelper.hh \
qpdf/QPDFObject.hh \
qpdf/QPDFObjectHandle.hh \
qpdf/QPDFObjectHelper.hh \
qpdf/QPDFObjGen.hh \
qpdf/QPDFOutlineDocumentHelper.hh \
qpdf/QPDFOutlineObjectHelper.hh \
qpdf/QPDFPageDocumentHelper.hh \
qpdf/QPDFPageLabelDocumentHelper.hh \
qpdf/QPDFPageObjectHelper.hh \
qpdf/QPDFSystemError.hh \
qpdf/QPDFTokenizer.hh \
qpdf/QPDFWriter.hh \
qpdf/QPDFXRefEntry.hh \
qpdf/QTC.hh \
qpdf/QUtil.hh \
qpdf/RandomDataProvider.hh \
qpdf/Types.h
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dllINCLUDEPATH += $$PWD/qpdf
DEPENDPATH += $$PWD/qpdf
I get it working using the configuration bellow :
My.pro :
#-------------------------------------------------
#
# Project created by QtCreator 2019-04-01T16:52:28
#
#-------------------------------------------------
QT += core gui
QT += axcontainer
QT += serialport
CONFIG += c++11 console
CONFIG -= app_bundle
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QTfillpdftest
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
qtfillpdf.cpp
HEADERS += \
qtfillpdf.h\
qpdf/Buffer.hh \
qpdf/BufferInputSource.hh \
qpdf/ClosedFileInputSource.hh \
qpdf/Constants.h \
qpdf/DLL.h \
qpdf/FileInputSource.hh \
qpdf/InputSource.hh \
qpdf/JSON.hh \
qpdf/Pipeline.hh \
qpdf/Pl_Buffer.hh \
qpdf/Pl_Concatenate.hh \
qpdf/Pl_Count.hh \
qpdf/Pl_DCT.hh \
qpdf/Pl_Discard.hh \
qpdf/Pl_Flate.hh \
qpdf/Pl_QPDFTokenizer.hh \
qpdf/Pl_RunLength.hh \
qpdf/Pl_StdioFile.hh \
qpdf/PointerHolder.hh \
qpdf/qpdf-c.h \
qpdf/QPDF.hh \
qpdf/QPDFAcroFormDocumentHelper.hh \
qpdf/QPDFAnnotationObjectHelper.hh \
qpdf/QPDFDocumentHelper.hh \
qpdf/QPDFExc.hh \
qpdf/QPDFFormFieldObjectHelper.hh \
qpdf/QPDFNameTreeObjectHelper.hh \
qpdf/QPDFNumberTreeObjectHelper.hh \
qpdf/QPDFObject.hh \
qpdf/QPDFObjectHandle.hh \
qpdf/QPDFObjectHelper.hh \
qpdf/QPDFObjGen.hh \
qpdf/QPDFOutlineDocumentHelper.hh \
qpdf/QPDFOutlineObjectHelper.hh \
qpdf/QPDFPageDocumentHelper.hh \
qpdf/QPDFPageLabelDocumentHelper.hh \
qpdf/QPDFPageObjectHelper.hh \
qpdf/QPDFSystemError.hh \
qpdf/QPDFTokenizer.hh \
qpdf/QPDFWriter.hh \
qpdf/QPDFXRefEntry.hh \
qpdf/QTC.hh \
qpdf/QUtil.hh \
qpdf/RandomDataProvider.hh \
qpdf/Types.h
FORMS += \
qtfillpdf.ui
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll
else:unix: LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll
INCLUDEPATH += $$PWD/qpdf
DEPENDPATH += $$PWD/qpdf
Function :
int qtfillpdf::qtfillpdfFile( char const* infilename , char const* outfilename,char const* value )
{
qDebug() << "qtfillpdf : 1 " << value;
// This is a contrived example that just goes through a file page
// by page and sets the value of any text fields it finds to a
// fixed value as given on the command line. The purpose here is
// to illustrate use of the helper classes around interactive
// forms.
QPDF qpdf;
qDebug() << "qtfillpdfFile : 1.1 " << value;
qpdf.processFile(infilename);
std::string nm;
nm= qpdf.getFilename();
qDebug() << "qtfillpdf : 2 " << nm.c_str() ;
// We will iterate through form fields by starting at the page
// level and looking at each field for each page. We could
// also called QPDFAcroFormDocumentHelper::getFormFields to
// iterate at the field level, but doing it as below
// illustrates how we can map from annotations to fields.
QPDFAcroFormDocumentHelper afdh(qpdf);
QPDFPageDocumentHelper pdh(qpdf);
std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages();
qDebug() << "qtfillpdf : 3 " ;
for (std::vector<QPDFPageObjectHelper>::iterator page_iter =
pages.begin();
page_iter != pages.end(); ++page_iter)
{
// Get all widget annotations for each page. Widget
// annotations are the ones that contain the details of
// what's in a form field.
std::vector<QPDFAnnotationObjectHelper> annotations =
afdh.getWidgetAnnotationsForPage(*page_iter);
for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter = annotations.begin();
annot_iter != annotations.end(); ++annot_iter)
{
// For each annotation, find its associated field. If
// it's a text field, set its value. This will
// automatically update the document to indicate that
// appearance streams need to be regenerated. At the
// time of this writing, qpdf doesn't have any helper
// code to assist with appearance stream generation,
// though there's nothing that prevents it from being
// possible.
//qDebug() << "qtfillpdf : 4 " << annot_iter->getAppearanceState().c_str() ;
QPDFFormFieldObjectHelper ffh =
afdh.getFieldForAnnotation(*annot_iter);
if (ffh.getFieldType() == "/Tx")
{
//qDebug() << "qtfillpdf : 5 " <<ffh.getChoices().front().c_str();
// Set the value. This will automatically set
// /NeedAppearances to true. If you don't want to
// do that, pass false as the second argument. For
// details see comments in
// QPDFFormFieldObjectHelper.hh.
ffh.setV(value);
qDebug() << "OK6" << value << " ffh.getValueAsString() : " <<ffh.getValueAsString().c_str();
}
}
}
// Write out a new file
QPDFWriter w(qpdf, outfilename);
w.setStaticID(true); // for testing only
w.write();
return 3;
}
void qtfillpdf::on_Browse_clicked()
{
///TODO : mettre le liens
QString s_configFileName;
QString outfilename = "OUT.pdf";
QString value="qfiller";
s_configFileName = QFileDialog::getOpenFileName(
this,
tr("Selectfile"),
"", tr("pdf Files (*.pdf)")
);
qDebug() << "File Name : " << s_configFileName ;
qtfillpdfFile(s_configFileName.toStdString().c_str(), outfilename.toStdString().c_str(), value.toStdString().c_str());
qDebug()<< " END_BROWSE :" << s_configFileName ;
}
Related
I need to reproduce the functionality of this C code but in typescript. The purpose of this code is mainly to simplify error checking as stated in JPL's The Power of Ten but I couldn't find a way to do it in TS.
#define ecall(retVal, l_call, format, ...) do { \
int _rv = (l_call); \
if(_rv < 0) { \
printf(format, __VA_ARGS__); \
return retVal; \
} \
else { \
check(); \
} \
} while(0)
I'm looking for fixture support in BOOST_DATA_TEST_CASE. I wrote following C++ macros for it, but may be somebody has something better?
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#define BOOST_FIXTURE_DATA_TEST_CASE_IMPL( arity, test_name, F, dataset, params ) \
struct test_name : public F { \
template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
static void test_method( BOOST_DATA_TEST_CASE_PARAMS( params ) ) \
{ \
BOOST_TEST_CHECKPOINT('"' << #test_name << "\" fixture entry."); \
test_name t; \
BOOST_TEST_CHECKPOINT('"' << #test_name << "\" entry."); \
BOOST_TEST_CONTEXT( "" \
BOOST_PP_SEQ_FOR_EACH(BOOST_DATA_TEST_CONTEXT, _, params)) \
t._impl(BOOST_PP_SEQ_ENUM(params)); \
BOOST_TEST_CHECKPOINT('"' << #test_name << "\" exit."); \
} \
private: \
template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
void _impl(BOOST_DATA_TEST_CASE_PARAMS( params )); \
}; \
\
BOOST_AUTO_TU_REGISTRAR( test_name )( \
boost::unit_test::data::ds_detail::make_test_case_gen<test_name>( \
BOOST_STRINGIZE( test_name ), \
__FILE__, __LINE__, \
boost::unit_test::data::make(dataset) ), \
boost::unit_test::decorator::collector::instance() ); \
\
template<BOOST_PP_ENUM_PARAMS(arity, typename Arg)> \
void test_name::_impl( BOOST_DATA_TEST_CASE_PARAMS( params ) ) \
/**/
#define BOOST_AUTO_DATA_TEST_CASE_WITH_PARAMS( test_name, dataset, ... ) \
BOOST_FIXTURE_DATA_TEST_CASE_IMPL( BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), \
test_name, BOOST_AUTO_TEST_CASE_FIXTURE, dataset, \
BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) ) \
/**/
#define BOOST_AUTO_DATA_TEST_CASE_NO_PARAMS( test_name, dataset ) \
BOOST_AUTO_DATA_TEST_CASE_WITH_PARAMS( test_name, dataset, sample ) \
/**/
#if BOOST_PP_VARIADICS_MSVC
#define BOOST_AUTO_DATA_TEST_CASE( ... ) \
BOOST_PP_CAT( \
BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \
BOOST_AUTO_DATA_TEST_CASE_NO_PARAMS, \
BOOST_AUTO_DATA_TEST_CASE_WITH_PARAMS) (__VA_ARGS__), ) \
/**/
#else
#define BOOST_AUTO_DATA_TEST_CASE( ... ) \
BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),2), \
BOOST_AUTO_DATA_TEST_CASE_NO_PARAMS, \
BOOST_AUTO_DATA_TEST_CASE_WITH_PARAMS) (__VA_ARGS__) \
/**/
#endif
Example of BOOST_DATA_TEST_CASE usage:
#include <boost/range/iterator_range.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
struct fixure
{
fixure() :
_Mydir(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("test-%%%%-%%%%-%%%%-%%%%"))
{
create_directory(_Mydir);
}
~fixure()
{
_TRY_BEGIN
remove_all(_Mydir);
_CATCH_ALL
_CATCH_END
}
boost::filesystem::path const _Mydir;
};
BOOST_FIXTURE_TEST_SUITE(suite, fixure)
namespace {
std::array<char const *, 4> const _Ourdata = { "A", "B", "C", "D" };
}
BOOST_AUTO_DATA_TEST_CASE(test, _Ourdata, _Str)
{
BOOST_REQUIRE(_Str);
BOOST_REQUIRE(is_directory(_Mydir));
auto const _File = _Mydir / _Str;
BOOST_TEST_MESSAGE(_File);
std::fstream _Stream;
_Stream.open(_File.c_str(), std::ios::out);
_Stream << _Str;
_Stream.close();
BOOST_REQUIRE(is_regular_file(_File));
}
BOOST_AUTO_TEST_SUITE_END()
Output in test_suite mode:
Running 4 test cases...
Entering test module "example"
Entering test suite "suite"
Entering test case "test"
"C:\Users\XXX\AppData\Local\Temp\test-4445-a983-8ba6-09ef\A"
Failure occurred in a following context:
_Str = A;
Leaving test case "test"; testing time: 17ms
Entering test case "test"
"C:\Users\XXX\AppData\Local\Temp\test-d4c4-c5f6-6154-7200\B"
Failure occurred in a following context:
_Str = B;
Leaving test case "test"; testing time: 10ms
Entering test case "test"
"C:\Users\XXX\AppData\Local\Temp\test-9f96-4f2c-b132-c541\C"
Failure occurred in a following context:
_Str = C;
Leaving test case "test"; testing time: 9ms
Entering test case "test"
"C:\Users\XXX\AppData\Local\Temp\test-f0cf-962c-aed3-1cf8\D"
Failure occurred in a following context:
_Str = D;
Leaving test case "test"; testing time: 10ms
Leaving test suite "suite"; testing time: 61ms
Leaving test module "example"; testing time: 76ms
*** No errors detected
Update: Test suite was updated to std::array<> using
As of Boost 1.62, you can use BOOST_DATA_TEST_CASE_F for this:
Declares and registers a data-driven test case, using a particular dataset and a fixture.
BOOST_DATA_TEST_CASE_F(my_fixture, test_case_name, dataset, var1, var2..., varN)
Reference:
https://www.boost.org/doc/libs/1_62_0/libs/test/doc/html/boost_test/utf_reference/test_org_reference/test_org_boost_test_dataset_fixture.html
I'm currently trying to integrate an ASN.1 decoder code written in C to the C++ Builder XE6 environment. I've encountered some problems while using the Singly linked tail queue support provided by the library, with the following call :
asn1p_wsyntx_chunk_t *wc;
while((wc = TQ_REMOVE(&(wx->chunks), next)))
asn1p_wsyntx_chunk_free(wc);
The error that I get is :
member reference type 'int' is not a pointer
The definitions of asn1p_wsyntx_chunk_t (wc) and asn1p_wsyntx_t (wx) are :
typedef struct asn1p_wsyntx_chunk_s {
enum {
WC_LITERAL,
WC_WHITESPACE,
WC_FIELD,
WC_OPTIONALGROUP
} type;
/*
* WC_LITERAL -> {token}
* WC_WHITESPACE -> {token}
* WC_FIELD -> {token}
* WC_OPTIONALGROUP -> {syntax}
*/
union {
char *token;
struct asn1p_wsyntx_s *syntax;
} content;
TQ_ENTRY(struct asn1p_wsyntx_chunk_s) next;
} asn1p_wsyntx_chunk_t;
typedef struct asn1p_wsyntx_s {
TQ_HEAD(struct asn1p_wsyntx_chunk_s) chunks;
} asn1p_wsyntx_t;
The code of the Singly linked tail is this one :
#define TQ_HEAD(type) \
struct { \
type *tq_head; \
type**tq_tail; \
}
#define TQ_MOVE(to, from) do { \
if(&(TQ_FIRST(from)) == (from)->tq_tail) { \
TQ_INIT(to); \
} else { \
(to)->tq_head = (from)->tq_head; \
(to)->tq_tail = (from)->tq_tail; \
} \
TQ_INIT(from); \
} while(0)
#define TQ_ENTRY(type) \
struct { \
type *tq_next; \
}
#define TQ_FIRST(headp) ((headp)->tq_head)
#define TQ_NEXT(el, field) ((el)->field.tq_next)
#define TQ_INIT(head) do { \
TQ_FIRST((head)) = 0; \
(head)->tq_tail = &TQ_FIRST((head)); \
} while(0)
#define TQ_FOR(var, head, field) \
for((var) = TQ_FIRST((head)); \
(var); (var) = TQ_NEXT((var), field))
/* MSVC does not have decltype(), cannot prevent side effects! */
#define TQ_ADD(head, xel, field) do { \
decltype(xel) __el = (xel); \
assert(TQ_NEXT((__el), field) == 0); \
*(head)->tq_tail = (__el); \
(head)->tq_tail = &TQ_NEXT((__el), field); \
} while(0)
#define TQ_CONCAT(head1, head2, field) do { \
if(TQ_FIRST(head2)) { \
*(head1)->tq_tail = (head2)->tq_head; \
(head1)->tq_tail = (head2)->tq_tail; \
TQ_INIT(head2); \
} \
} while(0)
/*
* Remove the first element and return it.
*/
#define TQ_REMOVE(head, field) ({ \
auto __fel = TQ_FIRST((head)); \
if(__fel == 0 \
|| (TQ_FIRST((head)) = TQ_NEXT(__fel, field)) \
== 0) { \
(head)->tq_tail = &TQ_FIRST((head)); \
} else { \
TQ_NEXT(__fel, field) = 0; \
} \
__fel; })
I've tried different casts but without success.
Thank you for your help !
EDIT :
Here is the code that I get for this call once preprocessed :
asn1p_wsyntx_chunk_t *wc;
while((wc = ({ auto __fel = (((&(wx->chunks)))->tq_head); if(__fel == 0 ||
((((&(wx->chunks)))->tq_head) = ((__fel)->next.tq_next)) == 0)
{ (&(wx->chunks))->tq_tail = &(((&(wx->chunks)))->tq_head); }
else { ((__fel)->next.tq_next) = 0; } __fel; })))
asn1p_wsyntx_chunk_free(wc);
I use QtCreator and gdb 7.7. I have an example macro:
#define getMax(a,b) ((a) > (b) ? (a) : (b))
Then somewhere in the code a breakpoint is set when that macro is used:
break at line: x = getMax(v, z);
Is it possible to see expanded macro during debugging ?
Edit1 How to check value of the variable, for example func ## Index or curr after expanded following macro:
#define WRAPABLE_HND_FUNCTN(func, ...) \
{ \
enum { num = func ## Index }; \
unsigned int curr = mCurrFunction[num]; \
while (mCurrFunction[num] < mInterface.size () && \
!mInterface[mCurrFunction[num]].enabled[num]) \
++mCurrFunction[num]; \
if (mCurrFunction[num] < mInterface.size ()) \
{ \
mInterface[mCurrFunction[num]++].obj-> func (__VA_ARGS__); \
mCurrFunction[num] = curr; \
return; \
} \
mCurrFunction[num] = curr; \
}
When I execute print handleEventIndex (which was func ## Index) I get:
554print handleEventIndex
&"print handleEventIndex\n"
~"$2 = CompScreen::handleEventIndex"
~"\n"
554^done
For print curr I get:
555print curr
&"print curr\n"
&"No symbol \"curr\" in current context.\n"
555^error,msg="No symbol \"curr\" in current context."
You will need to compile your program with full macro support:
g++ -ggdb3
When debugging on Qt Creator, enable the Debugger Log view and type the following in the resulting console:
macro expand getMax(v, z)
More information on the GDB Manual.
I cannot understand: "Why this reassurance?".
This is wrapper for custom native function from dart/runtime/vm/native_entry.cc:
It intended for the Dart programmers that want write native extensions.
void NativeEntry::NativeCallWrapper(Dart_NativeArguments args,
Dart_NativeFunction func) {
CHECK_STACK_ALIGNMENT;
VERIFY_ON_TRANSITION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
Isolate* isolate = arguments->isolate();
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
ApiLocalScope* current_top_scope = state->top_scope();
ApiLocalScope* scope = state->reusable_scope();
TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func));
if (scope == NULL) {
scope = new ApiLocalScope(current_top_scope,
isolate->top_exit_frame_info());
ASSERT(scope != NULL);
} else {
scope->Reinit(isolate,
current_top_scope,
isolate->top_exit_frame_info());
state->set_reusable_scope(NULL);
}
state->set_top_scope(scope); // New scope is now the top scope.
func(args);
ASSERT(current_top_scope == scope->previous());
state->set_top_scope(current_top_scope); // Reset top scope to previous.
if (state->reusable_scope() == NULL) {
scope->Reset(isolate); // Reset the old scope which we just exited.
state->set_reusable_scope(scope);
} else {
ASSERT(state->reusable_scope() != scope);
delete scope;
}
DEOPTIMIZE_ALOT;
VERIFY_ON_TRANSITION;
}
This wrapper with all unnecessary checks that it performs at every invocation of wrapped native function makes these functions uncompetitive in comparison to what uses developers for themselves.
This is MACRO for defining native function from dart/runtime/vm/native_entry.h:
#define DEFINE_NATIVE_ENTRY(name, argument_count) \
static RawObject* DN_Helper##name(Isolate* isolate, \
NativeArguments* arguments); \
void NATIVE_ENTRY_FUNCTION(name)(Dart_NativeArguments args) { \
CHECK_STACK_ALIGNMENT; \
VERIFY_ON_TRANSITION; \
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); \
ASSERT(arguments->NativeArgCount() == argument_count); \
TRACE_NATIVE_CALL("%s", ""#name); \
{ \
StackZone zone(arguments->isolate()); \
SET_NATIVE_RETVAL(arguments, \
DN_Helper##name(arguments->isolate(), arguments)); \
DEOPTIMIZE_ALOT; \
} \
VERIFY_ON_TRANSITION; \
} \
static RawObject* DN_Helper##name(Isolate* isolate, \
NativeArguments* arguments)
I know that it works directly with RawObject. This is normal.
But I can not find in it all of these tests, which are performed in each call, as in the above wrapper.
I lose heart when I see that my functions work on the 3000% slower than the analogues defined via DEFINE_NATIVE_ENTRY.
P.S
My native function that does NOTHING and does not returns ANYTHING works on the 500% slower than (for example) this function.
#define TYPED_DATA_GETTER(getter, object, access_size) \
DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
if (instance.IsTypedData()) { \
const TypedData& array = TypedData::Cast(instance); \
RangeCheck(offsetInBytes.Value(), access_size, \
array.LengthInBytes(), access_size); \
return object::New(array.getter(offsetInBytes.Value())); \
} \
if (instance.IsExternalTypedData()) { \
const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
RangeCheck(offsetInBytes.Value(), access_size, \
array.LengthInBytes(), access_size); \
return object::New(array.getter(offsetInBytes.Value())); \
} \
const String& error = String::Handle(String::NewFormatted( \
"Expected a TypedData object but found %s", instance.ToCString())); \
Exceptions::ThrowArgumentError(error); \
return object::null(); \
} \
Is there any way to write lightweight native functions that not requires all of these scope?
This is an old question, but native libraries are definitely not the greatest and are pretty heavy-weight. These days we typically recommend that users look at using dart:ffi for C-interop, which is more performant than native extensions and arguably much easier to use.