Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perform search for setResolution linearly? #220

Merged
merged 1 commit into from
Jun 12, 2022

Conversation

Andersama
Copy link
Contributor

As mentioned in #193 the issue stems from repeated usage of getAddress(). It doesn't seem to me to be necessary to use iterators to sort out the performance issue in the library, just a general avoidance of getAddress() outside index based functions.

Since getAddress() appears to be used to do a bit more than iterate through addresses I added validAddress() as an additional condition, it might not be needed.

I only found two locations where this appears to happen. both are in setResolution functions. So #193 may be resolved entirely by this. General advice to users of the library may be to avoid index based functions inside loops. This might be where an "iterator" interface may be useful inside the class, such that performing functions across devices remains somewhat linear.

As mentioned in milesburton#193 the issue stems from repeated usage of getAddress(). It doesn't seem to me to be necessary to use iterators to sort out the performance issue in the library, just a general avoidance of getAddress() outside index based functions. 

Since getAddress() appears to be used to do a bit more than iterate through addresses I added validAddress() as an additional condition, it might not be needed.

I only found two locations where this appears to happen so milesburton#193 may be resolved entirely by this. General advice to users of the library may be to avoid index based functions inside loops. This might be where an "iterator" interface may be useful inside the class, such that performing functions across devices remains somewhat linear.
@RobTillaart
Copy link
Contributor

@milesburton
Can you approve the build ?

Copy link
Contributor

@RobTillaart RobTillaart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me

@milesburton milesburton merged commit f484fe9 into milesburton:master Jun 12, 2022
@milesburton
Copy link
Owner

Thanks all, merged

@Andersama
Copy link
Contributor Author

No problem, I am using the library after all. Since the original issue mentioned it I gave iterators a thought because search() would function like ++, but since any call to search() or reset_search() messes with following calls I didn't bother.

I didn't find that other one wire library that was mentioned, if you know where or what that was I'd be happy to take a look at it to see if it does anything different. The current one seems fairly small so I don't get the impression there's much that could be different.

My adhoc solution for ease of use for making everything else linear was this template function.

	template<typename Callback>
	bool forEachValidAddress(Callback callback) {
		bool last_result = false;
		DeviceAddress addr;
		
		_wire->reset_search();
		while(_wire->search(addr)) {
			if (validAddress(addr) && !(last_result = callback((uint8_t*)addr))) {
				break;
			}
		}
		
		return last_result;
	}

So that I could things like this:

bool process_address(uint8_t* addr) {
    float temp = sensors.getTempF(addr);

    if (temp < min_temp)
      min_temp = temp;
    if (temp > max_temp)
      max_temp = temp;
    
    device_count++;
    return true;
}
  
sensors.forEachValidAddress(process_address);

@RobTillaart
Copy link
Contributor

Nice construct.
Question, if the call back fails - for whatever reason - the while loop is ended.
I assume this can be prematurely as not all are processed?

Should break not be continue?

A variation on your template, returns true only if all valid addresses are processed correctly

  template<typename Callback>
  bool forEachValidAddress(Callback callback) {
    bool last_result = true;     //  changed
    DeviceAddress addr;
		
    _wire->reset_search();
    while(_wire->search(addr)) {
      if (validAddress(addr) && !(last_result &&= callback((uint8_t*)addr))) {   //  changed
        continue;   // changed
      }
    }
  return last_result;   
  }

https://github.com/pstolarz/OneWireNg this one?

@Andersama
Copy link
Contributor Author

Andersama commented Jun 14, 2022

Well, it's a boolean so the logic can be flipped eaither way, I was using false to exit the loop prematurely if needed. Say for example we were writing a loop to check if any temperature probe met some threshold, past the point you've seen a temperature probe hit the threshold you might not need to check any of the remaining devices.

Since we ignore invalidAddresses that case would always be continue. The edit you made with your continue actually doesn't even need the continue since it's about to jump to the top of the loop anyway, at which point the callback doesn't need to have a return value. Which actually could be a way you specialize the template, you could for example have explicitly added these to the header:

bool forEachValidAddress(bool(*callback)(uint8_t*)) {
    bool last_result = true;
    DeviceAddress addr;
		
    _wire->reset_search();
    while(_wire->search(addr)) {
      if (validAddress(addr) && !(last_result &&= callback((uint8_t*)addr))) {
        break;
      }
    }
  return last_result;  
}
bool forEachValidAddress(void(*callback)(uint8_t*)) {
    bool last_result = true;
    DeviceAddress addr;
		
    _wire->reset_search();
    while(_wire->search(addr)) {
      if (validAddress(addr)) {
        callback((uint8_t*)addr)
      }
    }
  return last_result;  
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants