[libcamera-devel,v2,2/4] v4l2: Replace manual loop counters with utils::enumerate()
diff mbox series

Message ID 20210515040511.23294-3-laurent.pinchart@ideasonboard.com
State Accepted
Delegated to: Laurent Pinchart
Headers show
Series
  • libcamera: Simplify range-based for loop counters
Related show

Commit Message

Laurent Pinchart May 15, 2021, 4:05 a.m. UTC
Use the newly introduced utils::enumerate() to replace manual loop
counters. A local variable is needed, as utils::enumerate() requires an
lvalue reference.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
Changes since v1:

- Use structured bindings
---
 src/v4l2/v4l2_compat_manager.cpp | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

Comments

Niklas Söderlund May 15, 2021, 9:18 a.m. UTC | #1
Hi Laurent,

Thanks for your work.

On 2021-05-15 07:05:09 +0300, Laurent Pinchart wrote:
> Use the newly introduced utils::enumerate() to replace manual loop
> counters. A local variable is needed, as utils::enumerate() requires an
> lvalue reference.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>

> ---
> Changes since v1:
> 
> - Use structured bindings
> ---
>  src/v4l2/v4l2_compat_manager.cpp | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
> index 90c0f0121a32..96dbcdf28f04 100644
> --- a/src/v4l2/v4l2_compat_manager.cpp
> +++ b/src/v4l2/v4l2_compat_manager.cpp
> @@ -23,6 +23,7 @@
>  #include <libcamera/camera_manager.h>
>  
>  #include "libcamera/internal/log.h"
> +#include "libcamera/internal/utils.h"
>  
>  #include "v4l2_camera_file.h"
>  
> @@ -81,11 +82,10 @@ int V4L2CompatManager::start()
>  	 * For each Camera registered in the system, a V4L2CameraProxy gets
>  	 * created here to wrap a camera device.
>  	 */
> -	unsigned int index = 0;
> -	for (auto &camera : cm_->cameras()) {
> +	auto cameras = cm_->cameras();
> +	for (auto [index, camera] : utils::enumerate(cameras)) {
>  		V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera);
>  		proxies_.emplace_back(proxy);
> -		++index;
>  	}
>  
>  	return 0;
> @@ -117,11 +117,10 @@ int V4L2CompatManager::getCameraIndex(int fd)
>  	if (!target)
>  		return -1;
>  
> -	unsigned int index = 0;
> -	for (auto &camera : cm_->cameras()) {
> +	auto cameras = cm_->cameras();
> +	for (auto [index, camera] : utils::enumerate(cameras)) {
>  		if (camera == target)
>  			return index;
> -		++index;
>  	}
>  
>  	return -1;
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Kieran Bingham May 17, 2021, 12:54 p.m. UTC | #2
Hi Laurent,

On 15/05/2021 05:05, Laurent Pinchart wrote:
> Use the newly introduced utils::enumerate() to replace manual loop
> counters. A local variable is needed, as utils::enumerate() requires an
> lvalue reference.

So this is not possible?

	for (auto [index, camera] : utils::enumerate(cm_->cameras()) {

I guess that's fine, but will it be obvious to someone trying to use it
that they need to move the thing to enumerate to a local variable if
it's not there?

I probably really don't want to know - but why does it need this?
It seems like an odd limitation, but if it's just a small corner case,
then I don't mind having it split out. It helps keep line lengths
shorter anyway...?

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>


> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> Changes since v1:
> 
> - Use structured bindings
> ---
>  src/v4l2/v4l2_compat_manager.cpp | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
> index 90c0f0121a32..96dbcdf28f04 100644
> --- a/src/v4l2/v4l2_compat_manager.cpp
> +++ b/src/v4l2/v4l2_compat_manager.cpp
> @@ -23,6 +23,7 @@
>  #include <libcamera/camera_manager.h>
>  
>  #include "libcamera/internal/log.h"
> +#include "libcamera/internal/utils.h"
>  
>  #include "v4l2_camera_file.h"
>  
> @@ -81,11 +82,10 @@ int V4L2CompatManager::start()
>  	 * For each Camera registered in the system, a V4L2CameraProxy gets
>  	 * created here to wrap a camera device.
>  	 */
> -	unsigned int index = 0;
> -	for (auto &camera : cm_->cameras()) {
> +	auto cameras = cm_->cameras();
> +	for (auto [index, camera] : utils::enumerate(cameras)) {
>  		V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera);
>  		proxies_.emplace_back(proxy);
> -		++index;
>  	}
>  
>  	return 0;
> @@ -117,11 +117,10 @@ int V4L2CompatManager::getCameraIndex(int fd)
>  	if (!target)
>  		return -1;
>  
> -	unsigned int index = 0;
> -	for (auto &camera : cm_->cameras()) {
> +	auto cameras = cm_->cameras();
> +	for (auto [index, camera] : utils::enumerate(cameras)) {
>  		if (camera == target)
>  			return index;
> -		++index;
>  	}
>  
>  	return -1;
>
Laurent Pinchart May 17, 2021, 4:36 p.m. UTC | #3
Hi Kieran,

On Mon, May 17, 2021 at 01:54:08PM +0100, Kieran Bingham wrote:
> On 15/05/2021 05:05, Laurent Pinchart wrote:
> > Use the newly introduced utils::enumerate() to replace manual loop
> > counters. A local variable is needed, as utils::enumerate() requires an
> > lvalue reference.
> 
> So this is not possible?
> 
> 	for (auto [index, camera] : utils::enumerate(cm_->cameras()) {

Unfortunately not :-(

> I guess that's fine, but will it be obvious to someone trying to use it
> that they need to move the thing to enumerate to a local variable if
> it's not there?

The compiler should make it obvious:

../../src/v4l2/v4l2_compat_manager.cpp: In member function ‘int V4L2CompatManager::start()’:
../../src/v4l2/v4l2_compat_manager.cpp:85:53: error: no matching function for call to ‘enumerate(std::vector<std::shared_ptr<libcamera::Camera> >)’
   85 |         for (auto [index, camera] : utils::enumerate(cm_->cameras())) {

utils::enumerate() takes an lvalue reference, and cm_->cameras() is an
rvalue.

> I probably really don't want to know - but why does it need this?

https://en.cppreference.com/w/cpp/language/range-for#Temporary_range_expression

cm_->cameras() returns a temporay value, which is passed to
utils::enumerate(). utils::enumerate() returns another temporary that
stores a reference to cm_->cameras(). The lifetime of the second
temporary is extended to the whole loop, but the lifetime of the first
temporary isn't.

> It seems like an odd limitation, but if it's just a small corner case,
> then I don't mind having it split out. It helps keep line lengths
> shorter anyway...?
> 
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> > Changes since v1:
> > 
> > - Use structured bindings
> > ---
> >  src/v4l2/v4l2_compat_manager.cpp | 11 +++++------
> >  1 file changed, 5 insertions(+), 6 deletions(-)
> > 
> > diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
> > index 90c0f0121a32..96dbcdf28f04 100644
> > --- a/src/v4l2/v4l2_compat_manager.cpp
> > +++ b/src/v4l2/v4l2_compat_manager.cpp
> > @@ -23,6 +23,7 @@
> >  #include <libcamera/camera_manager.h>
> >  
> >  #include "libcamera/internal/log.h"
> > +#include "libcamera/internal/utils.h"
> >  
> >  #include "v4l2_camera_file.h"
> >  
> > @@ -81,11 +82,10 @@ int V4L2CompatManager::start()
> >  	 * For each Camera registered in the system, a V4L2CameraProxy gets
> >  	 * created here to wrap a camera device.
> >  	 */
> > -	unsigned int index = 0;
> > -	for (auto &camera : cm_->cameras()) {
> > +	auto cameras = cm_->cameras();
> > +	for (auto [index, camera] : utils::enumerate(cameras)) {
> >  		V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera);
> >  		proxies_.emplace_back(proxy);
> > -		++index;
> >  	}
> >  
> >  	return 0;
> > @@ -117,11 +117,10 @@ int V4L2CompatManager::getCameraIndex(int fd)
> >  	if (!target)
> >  		return -1;
> >  
> > -	unsigned int index = 0;
> > -	for (auto &camera : cm_->cameras()) {
> > +	auto cameras = cm_->cameras();
> > +	for (auto [index, camera] : utils::enumerate(cameras)) {
> >  		if (camera == target)
> >  			return index;
> > -		++index;
> >  	}
> >  
> >  	return -1;
Laurent Pinchart May 18, 2021, 10:42 a.m. UTC | #4
Hi Kieran,

On Mon, May 17, 2021 at 07:36:43PM +0300, Laurent Pinchart wrote:
> On Mon, May 17, 2021 at 01:54:08PM +0100, Kieran Bingham wrote:
> > On 15/05/2021 05:05, Laurent Pinchart wrote:
> > > Use the newly introduced utils::enumerate() to replace manual loop
> > > counters. A local variable is needed, as utils::enumerate() requires an
> > > lvalue reference.
> > 
> > So this is not possible?
> > 
> > 	for (auto [index, camera] : utils::enumerate(cm_->cameras()) {
> 
> Unfortunately not :-(
> 
> > I guess that's fine, but will it be obvious to someone trying to use it
> > that they need to move the thing to enumerate to a local variable if
> > it's not there?
> 
> The compiler should make it obvious:
> 
> ../../src/v4l2/v4l2_compat_manager.cpp: In member function ‘int V4L2CompatManager::start()’:
> ../../src/v4l2/v4l2_compat_manager.cpp:85:53: error: no matching function for call to ‘enumerate(std::vector<std::shared_ptr<libcamera::Camera> >)’
>    85 |         for (auto [index, camera] : utils::enumerate(cm_->cameras())) {
> 
> utils::enumerate() takes an lvalue reference, and cm_->cameras() is an
> rvalue.

I'll add the following to the documentation of the function:

 * Note that the argument to enumerate() has to be an lvalue, as the lifetime
 * of any rvalue would not be extended to the whole for loop. The compiler will
 * complain if an rvalue is passed to the function, in which case it should be
 * stored in a local variable before the loop.

> > I probably really don't want to know - but why does it need this?
> 
> https://en.cppreference.com/w/cpp/language/range-for#Temporary_range_expression
> 
> cm_->cameras() returns a temporay value, which is passed to
> utils::enumerate(). utils::enumerate() returns another temporary that
> stores a reference to cm_->cameras(). The lifetime of the second
> temporary is extended to the whole loop, but the lifetime of the first
> temporary isn't.
> 
> > It seems like an odd limitation, but if it's just a small corner case,
> > then I don't mind having it split out. It helps keep line lengths
> > shorter anyway...?
> > 
> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > 
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > ---
> > > Changes since v1:
> > > 
> > > - Use structured bindings
> > > ---
> > >  src/v4l2/v4l2_compat_manager.cpp | 11 +++++------
> > >  1 file changed, 5 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
> > > index 90c0f0121a32..96dbcdf28f04 100644
> > > --- a/src/v4l2/v4l2_compat_manager.cpp
> > > +++ b/src/v4l2/v4l2_compat_manager.cpp
> > > @@ -23,6 +23,7 @@
> > >  #include <libcamera/camera_manager.h>
> > >  
> > >  #include "libcamera/internal/log.h"
> > > +#include "libcamera/internal/utils.h"
> > >  
> > >  #include "v4l2_camera_file.h"
> > >  
> > > @@ -81,11 +82,10 @@ int V4L2CompatManager::start()
> > >  	 * For each Camera registered in the system, a V4L2CameraProxy gets
> > >  	 * created here to wrap a camera device.
> > >  	 */
> > > -	unsigned int index = 0;
> > > -	for (auto &camera : cm_->cameras()) {
> > > +	auto cameras = cm_->cameras();
> > > +	for (auto [index, camera] : utils::enumerate(cameras)) {
> > >  		V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera);
> > >  		proxies_.emplace_back(proxy);
> > > -		++index;
> > >  	}
> > >  
> > >  	return 0;
> > > @@ -117,11 +117,10 @@ int V4L2CompatManager::getCameraIndex(int fd)
> > >  	if (!target)
> > >  		return -1;
> > >  
> > > -	unsigned int index = 0;
> > > -	for (auto &camera : cm_->cameras()) {
> > > +	auto cameras = cm_->cameras();
> > > +	for (auto [index, camera] : utils::enumerate(cameras)) {
> > >  		if (camera == target)
> > >  			return index;
> > > -		++index;
> > >  	}
> > >  
> > >  	return -1;
Kieran Bingham May 18, 2021, 10:43 a.m. UTC | #5
Hi Laurent,

On 18/05/2021 11:42, Laurent Pinchart wrote:
> Hi Kieran,
> 
> On Mon, May 17, 2021 at 07:36:43PM +0300, Laurent Pinchart wrote:
>> On Mon, May 17, 2021 at 01:54:08PM +0100, Kieran Bingham wrote:
>>> On 15/05/2021 05:05, Laurent Pinchart wrote:
>>>> Use the newly introduced utils::enumerate() to replace manual loop
>>>> counters. A local variable is needed, as utils::enumerate() requires an
>>>> lvalue reference.
>>>
>>> So this is not possible?
>>>
>>> 	for (auto [index, camera] : utils::enumerate(cm_->cameras()) {
>>
>> Unfortunately not :-(
>>
>>> I guess that's fine, but will it be obvious to someone trying to use it
>>> that they need to move the thing to enumerate to a local variable if
>>> it's not there?
>>
>> The compiler should make it obvious:
>>
>> ../../src/v4l2/v4l2_compat_manager.cpp: In member function ‘int V4L2CompatManager::start()’:
>> ../../src/v4l2/v4l2_compat_manager.cpp:85:53: error: no matching function for call to ‘enumerate(std::vector<std::shared_ptr<libcamera::Camera> >)’
>>    85 |         for (auto [index, camera] : utils::enumerate(cm_->cameras())) {
>>
>> utils::enumerate() takes an lvalue reference, and cm_->cameras() is an
>> rvalue.
> 
> I'll add the following to the documentation of the function:
> 
>  * Note that the argument to enumerate() has to be an lvalue, as the lifetime
>  * of any rvalue would not be extended to the whole for loop. The compiler will
>  * complain if an rvalue is passed to the function, in which case it should be
>  * stored in a local variable before the loop.

Perfect.

Patch
diff mbox series

diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
index 90c0f0121a32..96dbcdf28f04 100644
--- a/src/v4l2/v4l2_compat_manager.cpp
+++ b/src/v4l2/v4l2_compat_manager.cpp
@@ -23,6 +23,7 @@ 
 #include <libcamera/camera_manager.h>
 
 #include "libcamera/internal/log.h"
+#include "libcamera/internal/utils.h"
 
 #include "v4l2_camera_file.h"
 
@@ -81,11 +82,10 @@  int V4L2CompatManager::start()
 	 * For each Camera registered in the system, a V4L2CameraProxy gets
 	 * created here to wrap a camera device.
 	 */
-	unsigned int index = 0;
-	for (auto &camera : cm_->cameras()) {
+	auto cameras = cm_->cameras();
+	for (auto [index, camera] : utils::enumerate(cameras)) {
 		V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera);
 		proxies_.emplace_back(proxy);
-		++index;
 	}
 
 	return 0;
@@ -117,11 +117,10 @@  int V4L2CompatManager::getCameraIndex(int fd)
 	if (!target)
 		return -1;
 
-	unsigned int index = 0;
-	for (auto &camera : cm_->cameras()) {
+	auto cameras = cm_->cameras();
+	for (auto [index, camera] : utils::enumerate(cameras)) {
 		if (camera == target)
 			return index;
-		++index;
 	}
 
 	return -1;