patch 8.1.1631: displaying signs is inefficient

Problem:    Displaying signs is inefficient.
Solution:   Avoid making multiple calls to get information about a placed
            sign. (Yegappan Lakshmanan, closes #4586)
diff --git a/src/sign.c b/src/sign.c
index a67f3ec..cf75819 100644
--- a/src/sign.c
+++ b/src/sign.c
@@ -274,6 +274,20 @@
 }
 
 /*
+ * Lookup a sign by typenr. Returns NULL if sign is not found.
+ */
+    static sign_T *
+find_sign_by_typenr(int typenr)
+{
+    sign_T	*sp;
+
+    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+	if (sp->sn_typenr == typenr)
+	    return sp;
+    return NULL;
+}
+
+/*
  * Get the name of a sign by its typenr.
  */
     static char_u *
@@ -445,31 +459,44 @@
 }
 
 /*
- * Return the type number of the sign at line number 'lnum' in buffer 'buf'
- * which has the attribute specified by 'type'. Returns 0 if a sign is not
- * found at the line number or it doesn't have the specified attribute.
+ * Return the attributes of the first sign placed on line 'lnum' in buffer
+ * 'buf'. Used when refreshing the screen. Returns TRUE if a sign is found on
+ * 'lnum', FALSE otherwise.
  */
     int
-buf_getsigntype(
-    buf_T	*buf,
-    linenr_T	lnum,
-    int		type)	// SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL
+buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T *sattr)
 {
-    signlist_T	*sign;		// a sign in a b_signlist
+    signlist_T	*sign;
+    sign_T	*sp;
+
+    vim_memset(sattr, 0, sizeof(sign_attrs_T));
 
     FOR_ALL_SIGNS_IN_BUF(buf, sign)
-	if (sign->lnum == lnum
-		&& (type == SIGN_ANY
+    {
+	if (sign->lnum > lnum)
+	    // Signs are sorted by line number in the buffer. No need to check
+	    // for signs after the specified line number 'lnum'.
+	    break;
+
+	if (sign->lnum == lnum)
+	{
+	    sattr->typenr = sign->typenr;
+	    sp = find_sign_by_typenr(sign->typenr);
+	    if (sp == NULL)
+		return FALSE;
+
 # ifdef FEAT_SIGN_ICONS
-		    || (type == SIGN_ICON
-			&& sign_get_image(sign->typenr) != NULL)
+	    sattr->icon = sp->sn_image;
 # endif
-		    || (type == SIGN_TEXT
-			&& sign_get_text(sign->typenr) != NULL)
-		    || (type == SIGN_LINEHL
-			&& sign_get_attr(sign->typenr, TRUE) != 0)))
-	    return sign->typenr;
-    return 0;
+	    sattr->text = sp->sn_text;
+	    if (sattr->text != NULL && sp->sn_text_hl > 0)
+		sattr->texthl = syn_id2attr(sp->sn_text_hl);
+	    if (sp->sn_line_hl > 0)
+		sattr->linehl = syn_id2attr(sp->sn_line_hl);
+	    return TRUE;
+	}
+    }
+    return FALSE;
 }
 
 /*
@@ -571,8 +598,15 @@
     signlist_T	*sign;		// a sign in the signlist
 
     FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if (sign->lnum > lnum)
+	    // Signs are sorted by line number in the buffer. No need to check
+	    // for signs after the specified line number 'lnum'.
+	    break;
+
 	if (sign->lnum == lnum && sign_in_group(sign, groupname))
 	    return sign;
+    }
 
     return NULL;
 }
@@ -608,8 +642,15 @@
     signlist_T	*sign;		// a sign in the signlist
 
     FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if (sign->lnum > lnum)
+	    // Signs are sorted by line number in the buffer. No need to check
+	    // for signs after the specified line number 'lnum'.
+	    break;
+
 	if (sign->lnum == lnum && sign->typenr == typenr)
 	    return sign->id;
+    }
 
     return 0;
 }
@@ -626,9 +667,16 @@
     int		count = 0;
 
     FOR_ALL_SIGNS_IN_BUF(buf, sign)
+    {
+	if (sign->lnum > lnum)
+	    // Signs are sorted by line number in the buffer. No need to check
+	    // for signs after the specified line number 'lnum'.
+	    break;
+
 	if (sign->lnum == lnum)
 	    if (sign_get_image(sign->typenr) != NULL)
 		count++;
+    }
 
     return count;
 }
@@ -1792,48 +1840,6 @@
     vim_free(sp);
 }
 
-/*
- * Get highlighting attribute for sign "typenr".
- * If "line" is TRUE: line highl, if FALSE: text highl.
- */
-    int
-sign_get_attr(int typenr, int line)
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_typenr == typenr)
-	{
-	    if (line)
-	    {
-		if (sp->sn_line_hl > 0)
-		    return syn_id2attr(sp->sn_line_hl);
-	    }
-	    else
-	    {
-		if (sp->sn_text_hl > 0)
-		    return syn_id2attr(sp->sn_text_hl);
-	    }
-	    break;
-	}
-    return 0;
-}
-
-/*
- * Get text mark for sign "typenr".
- * Returns NULL if there isn't one.
- */
-    char_u *
-sign_get_text(int typenr)
-{
-    sign_T	*sp;
-
-    for (sp = first_sign; sp != NULL; sp = sp->sn_next)
-	if (sp->sn_typenr == typenr)
-	    return sp->sn_text;
-    return NULL;
-}
-
 # if defined(FEAT_SIGN_ICONS) || defined(PROTO)
     void *
 sign_get_image(