I am working on a project which involves Rust and Java. I need to be able to use the JNI from the Rust side, without the Java side calling invoking it (because it is not my code). So far, I have been able to ensure my DLL is injected (open a small window on keypress, I have been using this for debugging).
A shortened example of the relevant code is the following:
use jni::sys::{JNI_GetCreatedJavaVMs, JNIInvokeInterface_};
let jvm_ptr = null_mut() as *mut *mut *const JNIInvokeInterface_;
let count = null_mut();
// hasn't crashed
JNI_GetCreatedJavaVMs(jvm_ptr, 1, count); // https://docs.rs/jni/latest/jni/sys/fn.JNI_GetCreatedJavaVMs.html
// crashes
My question is this: is it possible to/how do I get a JNI environment in this situation?
With the help of the comments, I got that crash to stop happening. The trick was to pre-allocate an array.
let jvm_ptr = Vec::with_capacity(1).as_mut_ptr();
let count = null_mut();
JNI_GetCreatedJavaVMs(jvm_ptr, 1, count);
You can't chunk a null pointer into the vmBuf parameter and then tell it that vmBuf points to an array of length 1 via bufLen. Translating the C++ code linked above, I would do something like
let mut count: jint = 0;
let check = JNI_GetCreatedJavaVMs(null_mut(), 0, &mut count);
assert!(check == JNI_OK);
let mut vms = vec![null_mut(); count as usize];
let check = JNI_GetCreatedJavaVMs(vms.as_mut_ptr(), vms.len() as i32, &mut count);
assert!(check == JNI_OK);
assert!(vms.len() == count as usize);
though that's probably a bit overkill since there can only be one VM. Still, checking the count is probably a good idea.
I have been using this many years. It can be polished....
try {
// how many JVMs is there?
JNI_GetCreatedJavaVMs(NULL, 0, &number_of_JVMs);
}
catch (exception e)
{
int x = 0;
}
if (number_of_JVMs > 0)
{
JavaVM** buffer = new JavaVM * [number_of_JVMs];
JNI_GetCreatedJavaVMs(buffer, number_of_JVMs, &number_of_JVMs);
// 2. get the data
jvm_handle = buffer[0];
if (!jvm_handle == 0)
return true;
else return false;
}
Whenever I launch the following program, I get an empty screen rather than the string "hello":
use ncurses as n;
fn main() {
render::setup_ncurses();
let win = n::newwin(30, 30, 0, 0);
n::waddstr(win, "hello");
n::wrefresh(win);
// n::refresh(); <-- this doesn't work either
n::getch();
// n::wgetch(win); <-- doesn't work either
n::endwin();
}
With the setup function:
pub fn setup_ncurses() {
// Allows for wide characters
n::setlocale(n::LcCategory::all, "");
n::initscr();
// Captures signal sequences and no buffer
n::raw();
// F keys and arrows
n::keypad(n::stdscr(), true);
// Doesn't echo typed keys
n::noecho();
}
Is there some weird behavior with windows that I'm missing? This doesn't happen when using stdscr.
Change:
let win = n::newwin(30, 30, 0, 0);
for:
let win = n::subwin(n::stdscr(), 30, 30, 0, 0);
I've got code that looks like this:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
I'd like remove inactive items immediately after update them, inorder to avoid walking the list again. But if I add the commented-out lines, I get an error when I get to i++: "List iterator not incrementable". I tried some alternates which didn't increment in the for statement, but I couldn't get anything to work.
What's the best way to remove items as you are walking a std::list?
You have to increment the iterator first (with i++) and then remove the previous element (e.g., by using the returned value from i++). You can change the code to a while loop like so:
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i++); // alternatively, i = items.erase(i);
}
else
{
other_code_involving(*i);
++i;
}
}
You want to do:
i= items.erase(i);
That will correctly update the iterator to point to the location after the iterator you removed.
You need to do the combination of Kristo's answer and MSN's:
// Note: Using the pre-increment operator is preferred for iterators because
// there can be a performance gain.
//
// Note: As long as you are iterating from beginning to end, without inserting
// along the way you can safely save end once; otherwise get it at the
// top of each loop.
std::list< item * >::iterator iter = items.begin();
std::list< item * >::iterator end = items.end();
while (iter != end)
{
item * pItem = *iter;
if (pItem->update() == true)
{
other_code_involving(pItem);
++iter;
}
else
{
// BTW, who is deleting pItem, a.k.a. (*iter)?
iter = items.erase(iter);
}
}
Of course, the most efficient and SuperCool® STL savy thing would be something like this:
// This implementation of update executes other_code_involving(Item *) if
// this instance needs updating.
//
// This method returns true if this still needs future updates.
//
bool Item::update(void)
{
if (m_needsUpdates == true)
{
m_needsUpdates = other_code_involving(this);
}
return (m_needsUpdates);
}
// This call does everything the previous loop did!!! (Including the fact
// that it isn't deleting the items that are erased!)
items.remove_if(std::not1(std::mem_fun(&Item::update)));
I have sumup it, here is the three method with example:
1. using while loop
list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
2. using remove_if member funtion in list:
list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
3. using std::remove_if funtion combining with erase member function:
list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
4. using for loop , should note update the iterator:
list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Use std::remove_if algorithm.
Edit:
Work with collections should be like:
prepare collection.
process collection.
Life will be easier if you won't mix this steps.
std::remove_if. or list::remove_if ( if you know that you work with list and not with the TCollection )
std::for_each
The alternative for loop version to Kristo's answer.
You lose some efficiency, you go backwards and then forward again when deleting but in exchange for the extra iterator increment you can have the iterator declared in the loop scope and the code looking a bit cleaner. What to choose depends on priorities of the moment.
The answer was totally out of time, I know...
typedef std::list<item*>::iterator item_iterator;
for(item_iterator i = items.begin(); i != items.end(); ++i)
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i--);
}
else
{
other_code_involving(*i);
}
}
Here's an example using a for loop that iterates the list and increments or revalidates the iterator in the event of an item being removed during traversal of the list.
for(auto i = items.begin(); i != items.end();)
{
if(bool isActive = (*i)->update())
{
other_code_involving(*i);
++i;
}
else
{
i = items.erase(i);
}
}
items.remove_if(CheckItemNotActive);
Removal invalidates only the iterators that point to the elements that are removed.
So in this case after removing *i , i is invalidated and you cannot do increment on it.
What you can do is first save the iterator of element that is to be removed , then increment the iterator and then remove the saved one.
If you think of the std::list like a queue, then you can dequeue and enqueue all the items that you want to keep, but only dequeue (and not enqueue) the item you want to remove. Here's an example where I want to remove 5 from a list containing the numbers 1-10...
std::list<int> myList;
int size = myList.size(); // The size needs to be saved to iterate through the whole thing
for (int i = 0; i < size; ++i)
{
int val = myList.back()
myList.pop_back() // dequeue
if (val != 5)
{
myList.push_front(val) // enqueue if not 5
}
}
myList will now only have numbers 1-4 and 6-10.
Iterating backwards avoids the effect of erasing an element on the remaining elements to be traversed:
typedef list<item*> list_t;
for ( list_t::iterator it = items.end() ; it != items.begin() ; ) {
--it;
bool remove = <determine whether to remove>
if ( remove ) {
items.erase( it );
}
}
PS: see this, e.g., regarding backward iteration.
PS2: I did not thoroughly tested if it handles well erasing elements at the ends.
You can write
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive) {
i = items.erase(i);
} else {
other_code_involving(*i);
i++;
}
}
You can write equivalent code with std::list::remove_if, which is less verbose and more explicit
items.remove_if([] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
});
The std::vector::erase std::remove_if idiom should be used when items is a vector instead of a list to keep compexity at O(n) - or in case you write generic code and items might be a container with no effective way to erase single items (like a vector)
items.erase(std::remove_if(begin(items), end(items), [] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
}));
do while loop, it's flexable and fast and easy to read and write.
auto textRegion = m_pdfTextRegions.begin();
while(textRegion != m_pdfTextRegions.end())
{
if ((*textRegion)->glyphs.empty())
{
m_pdfTextRegions.erase(textRegion);
textRegion = m_pdfTextRegions.begin();
}
else
textRegion++;
}
I'd like to share my method. This method also allows the insertion of the element to the back of the list during iteration
#include <iostream>
#include <list>
int main(int argc, char **argv) {
std::list<int> d;
for (int i = 0; i < 12; ++i) {
d.push_back(i);
}
auto it = d.begin();
int nelem = d.size(); // number of current elements
for (int ielem = 0; ielem < nelem; ++ielem) {
auto &i = *it;
if (i % 2 == 0) {
it = d.erase(it);
} else {
if (i % 3 == 0) {
d.push_back(3*i);
}
++it;
}
}
for (auto i : d) {
std::cout << i << ", ";
}
std::cout << std::endl;
// result should be: 1, 3, 5, 7, 9, 11, 9, 27,
return 0;
}
I think you have a bug there, I code this way:
for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin();
itAudioChannel != audioChannels.end(); )
{
CAudioChannel *audioChannel = *itAudioChannel;
std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel;
itAudioChannel++;
if (audioChannel->destroyMe)
{
audioChannels.erase(itCurrentAudioChannel);
delete audioChannel;
continue;
}
audioChannel->Mix(outBuffer, numSamples);
}
I've code to show clock time with the timeLabel:UILabel in my app whit Swift3.
And that is:
override func viewWillAppear(_ animated: Bool) {
Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.currentTime), userInfo: nil, repeats: true)
}
func currentTime(){
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
if second % 2 == 0{
timeLabel.text = "\(hour):\(minutes)"
}else {
timeLabel.text = "\(hour) \(minutes)"
}
But when two points disappear between hour and minutes numbers, they are a little bit movement. How to fix that?
With a trick 😏 can be fix that.
By adding another label with same background color in else condition, Yup😉
For Swift 3:
var attributes = [String: AnyObject]()
attributes[NSForegroundColorAttributeName] = self.view.backgroundColor
let attributedString = NSAttributedString(string: ":", attributes: attributes)
label.attributedText = attributedString
I've tried and surprised how could not I do with ExtJS. Let me explain with a code block.
In jQuery
console.clear();
var a = {
b: 5,
c: 4,
o: {
l: 2,
p: 2
}
}
var b = {
k: 4,
l: 3,
c: 5,
o: {
m: 2,
l: 1
}
}
var ex = $.extend(true, a, b);
console.dir(ex)
Here is the output
ex = {
a: {
q: 2
},
b: 5,
c: 5,
o: {
l: 1,
p: 2,
m: 2
}
}
Ext apply, applyIf, copyTo does not worked like this. How can I produce the output in ExtJS?
Thanks in advance.
For a recent project, we adapted this sample code to produce the following method:
Ext.deepCopy = function(p, c) {
c = c || (p.constructor === Array ? [] : {});
for (var i in p) {
if (typeof p[i] === 'object' && p[i] !== null) {
c[i] = p[i].constructor === Array ? [] : {};
Ext.deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
};
Deep copying isn't supported in Ext. There are Ext.apply and Ext.applyIf but they both only work on the first level of a hash map and will override instead of merge any embedded arrays or hashes.
In fact the docs explicitly state that Ext.apply is meant to work on config objects, not that it matters but it's just to illustrate that it's not meant to be used as a merge utility function although it basically could if you only want to merge the first level/depth.
Use the Ext.Object.merge() method, that does exactly what you're looking for.