diff mbox series

[FFmpeg-devel,2.e/3] libavformat/protocols.c: avio_enum_protocols(): Create a macro for generating different loops

Message ID e1612f5aca374e248c4ccd6a52d85812@gmail.com
State New
Headers show
Series [FFmpeg-devel,2.e/3] libavformat/protocols.c: avio_enum_protocols(): Create a macro for generating different loops | expand

Checks

Context Check Description
andriy/configure warning Failed to apply patch

Commit Message

Michael Witten Aug. 11, 2021, 7 p.m. UTC
The function 'avio_enum_protocols()' iterates through the list of
protocols, looking for a protocol that has a certain non-zero
pointer-to-function; the exact pointer-to-function to use depends
on the the argument passed through the parameter 'output'.

* Before this commit, the parameter 'output' was being checked
  on every iteration, despite the fact that its value does not
  change.

* This commit explicitly separates out the different cases into
  their own loops (i.e., their own functions), so that 'output'
  need not be tested on each iteration.

* To aid maintenance, these separate functions are the expansion
  of a single macro that provides a generic implementation:

    AVIO_ENUM_PROTOCOLS(METHOD)

  One of the benefits of using a macro is that it does not depend
  on a compiler being able to optimize the code. Before deciding
  to use a macro for this purpose, it was attempted to write a
  generic version in terms of pure C code that also would not
  rely on magical optimizations; this involved type conversions
  on pointer arithmetic around 'offsetof()', but it turns out that
  Standard C (not to be confused with Actual C) has no reliable way
  to recover the value of a pointer-to-function from an object,
  so that avenue was ultimately abandoned for the sake of pure
  pedantry.
---
 libavformat/protocols.c | 37 +++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/protocols.c b/libavformat/protocols.c
index 9ce98968fa..4cb8ae0b63 100644
--- a/libavformat/protocols.c
+++ b/libavformat/protocols.c
@@ -91,18 +91,35 @@  const AVClass *ff_urlcontext_child_class_iterate(void **iter)
     return ret;
 }
 
-const char *avio_enum_protocols(void **const opaque, const int output)
+#define AVIO_ENUM_PROTOCOLS(METHOD) \
+    typedef const URLProtocol *const *Iterator; \
+    for(Iterator p = *opaque ? (Iterator)(*opaque) + 1 : url_protocols; *p; ++p) { \
+        if ((*p)->METHOD) { \
+            *opaque = (void *)p; \
+            return (*p)->name; \
+        } \
+    } \
+    *opaque = NULL; \
+    return NULL;
+
+static inline
+const char *avio_enum_protocols_for_output(void **const opaque)
 {
-    typedef const URLProtocol *const *Iterator;
-    for(Iterator p = *opaque ? (Iterator)(*opaque) + 1 : url_protocols; *p; ++p) {
-        if ((output && (*p)->url_write) || (!output && (*p)->url_read)) {
-            *opaque = (void *)p;
-            return (*p)->name;
-        }
-    }
+    AVIO_ENUM_PROTOCOLS(url_write);
+}
 
-    *opaque = NULL;
-    return NULL;
+static inline
+const char *avio_enum_protocols_for_input(void **const opaque)
+{
+    AVIO_ENUM_PROTOCOLS(url_read);
+}
+
+const char *avio_enum_protocols(void **const opaque, const int output)
+{
+    if (output)
+        return avio_enum_protocols_for_output(opaque);
+    else
+        return avio_enum_protocols_for_input(opaque);
 }
 
 const AVClass *avio_protocol_get_class(const char *name)