From 5d72a5b4c0fbc4786c118aecbc4adb8ba3046c46 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Fri, 6 Mar 2026 12:41:15 +0100 Subject: [PATCH 1/2] chore: upd uthash, add timsort (repl. qsort) scintilla care (iface check) scintill-call-wrapper update --- .gitignore | 1 + Build/scripts/check_scicall.py | 386 +++++++++++++++ src/Edit.c | 18 +- src/Encoding.c | 4 +- src/Helpers.c | 2 +- src/Helpers.h | 7 +- src/Notepad3.vcxproj | 4 + src/Notepad3.vcxproj.filters | 15 + src/SciCall.h | 463 +++++++++++++++++- src/Styles.c | 2 +- src/timsort/AUTHORS | 11 + src/timsort/LICENSE | 202 ++++++++ src/timsort/README.md | 156 ++++++ src/timsort/stresstest.c | 166 +++++++ src/timsort/timsort-impl.h | 837 +++++++++++++++++++++++++++++++++ src/timsort/timsort.c | 420 +++++++++++++++++ src/timsort/timsort.h | 65 +++ src/timsort/timsort_r.c | 18 + src/uthash/License.txt | 3 +- src/uthash/utarray.h | 25 +- src/uthash/uthash.h | 25 +- src/uthash/utlist.h | 41 +- src/uthash/utringbuffer.h | 2 +- src/uthash/utstack.h | 2 +- src/uthash/utstring.h | 149 +++--- 25 files changed, 2865 insertions(+), 159 deletions(-) create mode 100644 Build/scripts/check_scicall.py create mode 100644 src/timsort/AUTHORS create mode 100644 src/timsort/LICENSE create mode 100644 src/timsort/README.md create mode 100644 src/timsort/stresstest.c create mode 100644 src/timsort/timsort-impl.h create mode 100644 src/timsort/timsort.c create mode 100644 src/timsort/timsort.h create mode 100644 src/timsort/timsort_r.c diff --git a/.gitignore b/.gitignore index 223e0004b..5a32f6463 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ ehthumbs.db Thumbs.db .vscode +.venv .agent # C++ Junk # diff --git a/Build/scripts/check_scicall.py b/Build/scripts/check_scicall.py new file mode 100644 index 000000000..51278c9ab --- /dev/null +++ b/Build/scripts/check_scicall.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python3 +""" +check_scicall.py - Diff Scintilla.iface against SciCall.h + +Parses Scintilla.iface to find all fun/get/set messages and compares +against SciCall.h to find: + 1. iface messages NOT wrapped in SciCall.h (candidates to add) + 2. SciCall.h wrappers that don't match any iface message (stale/custom) + +Usage: + python Build/scripts/check_scicall.py + python Build/scripts/check_scicall.py --verbose + python Build/scripts/check_scicall.py --category Basics + python Build/scripts/check_scicall.py --generate +""" + +import argparse +import os +import re +import sys + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +REPO_ROOT = os.path.normpath(os.path.join(SCRIPT_DIR, "..", "..")) + +IFACE_PATH = os.path.join(REPO_ROOT, "scintilla", "include", "Scintilla.iface") +SCICALL_PATH = os.path.join(REPO_ROOT, "src", "SciCall.h") + +# iface type -> NP3 C type mapping +TYPE_MAP = { + "void": "void", + "position": "DocPos", + "line": "DocLn", + "colour": "COLORREF", + "colouralpha": "COLORALPHAREF", + "bool": "bool", + "int": "int", + "string": "const char*", + "stringresult": "char*", + "pointer": "sptr_t", + "cells": "const char*", + "textrange": "struct Sci_TextRange*", + "textrangefull": "struct Sci_TextRangeFull*", + "findtext": "struct Sci_TextToFind*", + "findtextfull": "struct Sci_TextToFindFull*", + "formatrange": "struct Sci_RangeToFormat*", + "formatrangefull": "struct Sci_RangeToFormatFull*", + "keymod": "size_t", +} + + +def map_type(iface_type): + """Map an iface type to an NP3 C type.""" + if iface_type in TYPE_MAP: + return TYPE_MAP[iface_type] + # Capitalized enum types -> int + if iface_type and iface_type[0].isupper(): + return "int" + return "int" + + +def parse_iface(path): + """Parse Scintilla.iface, returning a dict of uppercase_name -> info.""" + messages = {} + current_category = "Unknown" + + # Match: fun/get/set =() + msg_re = re.compile( + r"^(fun|get|set)\s+" # feature type + r"(\S+)\s+" # return type + r"(\w+)" # function name + r"=(\d+)" # message number + r"\(([^)]*)\)" # parameters + ) + cat_re = re.compile(r"^cat\s+(\w+)") + + with open(path, "r", encoding="utf-8") as f: + for line_no, line in enumerate(f, 1): + line = line.rstrip() + + cat_m = cat_re.match(line) + if cat_m: + current_category = cat_m.group(1) + continue + + if line.startswith("##") or line.startswith("#!"): + continue + + msg_m = msg_re.match(line) + if msg_m: + feat_type = msg_m.group(1) + ret_type = msg_m.group(2) + name = msg_m.group(3) + msg_num = int(msg_m.group(4)) + params_str = msg_m.group(5).strip() + upper_name = name.upper() + + messages[upper_name] = { + "name": name, + "upper": upper_name, + "type": feat_type, + "ret": ret_type, + "num": msg_num, + "params": params_str, + "category": current_category, + "line": line_no, + "raw": line, + } + + return messages + + +def parse_scicall(path): + """Parse SciCall.h, returning a dict of uppercase_msg -> info.""" + wrappers = {} + + # Match: DeclareSciCall{R,V}{0,01,1,2}(fn, MSG, ...) + decl_re = re.compile( + r"DeclareSciCall([RV])(0|01|1|2)\s*\(\s*(\w+)\s*,\s*(\w+)" + ) + # Also match commented-out declarations + commented_re = re.compile( + r"//~?\s*DeclareSciCall([RV])(0|01|1|2)\s*\(\s*(\w+)\s*,\s*(\w+)" + ) + + with open(path, "r", encoding="utf-8") as f: + for line_no, line in enumerate(f, 1): + line_stripped = line.rstrip() + + # Skip macro definitions (#define DeclareSciCall...) + if line_stripped.startswith("#define"): + continue + + # Check for commented-out declarations (track but mark) + cm = commented_re.match(line_stripped) + if cm: + upper_msg = cm.group(4) + wrappers[upper_msg] = { + "fn": cm.group(3), + "msg": upper_msg, + "macro_ret": cm.group(1), + "macro_params": cm.group(2), + "line": line_no, + "commented": True, + "raw": line_stripped, + } + continue + + dm = decl_re.search(line_stripped) + if dm: + upper_msg = dm.group(4) + wrappers[upper_msg] = { + "fn": dm.group(3), + "msg": upper_msg, + "macro_ret": dm.group(1), + "macro_params": dm.group(2), + "line": line_no, + "commented": False, + "raw": line_stripped, + } + + return wrappers + + +def parse_param(param_str): + """Parse a single iface param like 'position pos' or '' into (type, name).""" + param_str = param_str.strip() + if not param_str: + return None, None + # Handle default values like 'int defaultValue' + parts = param_str.split() + if len(parts) >= 2: + return parts[0], parts[1].split("=")[0] + elif len(parts) == 1: + return parts[0], "param" + return None, None + + +def generate_wrapper(msg): + """Generate a DeclareSciCall* line for an iface message.""" + name = msg["name"] + upper = msg["upper"] + ret_type = msg["ret"] + params_str = msg["params"] + + # Parse return type + c_ret = map_type(ret_type) + is_void = (ret_type == "void") + + # Parse parameters + if "," in params_str: + wp_str, lp_str = params_str.split(",", 1) + else: + wp_str = params_str + lp_str = "" + + wp_type, wp_name = parse_param(wp_str) + lp_type, lp_name = parse_param(lp_str) + + has_wp = wp_type is not None + has_lp = lp_type is not None + + # Determine macro variant + rv = "V" if is_void else "R" + + if has_wp and has_lp: + variant = "2" + elif has_wp and not has_lp: + variant = "1" + elif not has_wp and has_lp: + variant = "01" + else: + variant = "0" + + macro = f"DeclareSciCall{rv}{variant}" + + # Build arguments + if variant == "0": + if is_void: + return f"{macro}({name}, {upper});" + else: + return f"{macro}({name}, {upper}, {c_ret});" + elif variant == "1": + c_wp = map_type(wp_type) + if is_void: + return f"{macro}({name}, {upper}, {c_wp}, {wp_name});" + else: + return f"{macro}({name}, {upper}, {c_ret}, {c_wp}, {wp_name});" + elif variant == "01": + c_lp = map_type(lp_type) + if is_void: + return f"{macro}({name}, {upper}, {c_lp}, {lp_name});" + else: + return f"{macro}({name}, {upper}, {c_ret}, {c_lp}, {lp_name});" + elif variant == "2": + c_wp = map_type(wp_type) + c_lp = map_type(lp_type) + if is_void: + return f"{macro}({name}, {upper}, {c_wp}, {wp_name}, {c_lp}, {lp_name});" + else: + return f"{macro}({name}, {upper}, {c_ret}, {c_wp}, {wp_name}, {c_lp}, {lp_name});" + + return f"// TODO: {name}" + + +def main(): + parser = argparse.ArgumentParser( + description="Diff Scintilla.iface against SciCall.h to find unwrapped messages" + ) + parser.add_argument( + "--verbose", "-v", action="store_true", + help="Show detailed info for each unwrapped message" + ) + parser.add_argument( + "--category", "-c", type=str, default=None, + help="Filter to a specific iface category (e.g. Basics, Provisional, Deprecated)" + ) + parser.add_argument( + "--show-wrapped", "-w", action="store_true", + help="Also list messages that ARE wrapped (for completeness check)" + ) + parser.add_argument( + "--generate", "-g", action="store_true", + help="Generate DeclareSciCall* lines for all unwrapped non-deprecated messages" + ) + parser.add_argument( + "--iface", type=str, default=IFACE_PATH, + help=f"Path to Scintilla.iface (default: {IFACE_PATH})" + ) + parser.add_argument( + "--scicall", type=str, default=SCICALL_PATH, + help=f"Path to SciCall.h (default: {SCICALL_PATH})" + ) + args = parser.parse_args() + + if not os.path.isfile(args.iface): + print(f"Error: {args.iface} not found", file=sys.stderr) + sys.exit(1) + if not os.path.isfile(args.scicall): + print(f"Error: {args.scicall} not found", file=sys.stderr) + sys.exit(1) + + all_iface_msgs = parse_iface(args.iface) + scicall_wrappers = parse_scicall(args.scicall) + + # Apply category filter for unwrapped/wrapped analysis + if args.category: + iface_msgs = { + k: v for k, v in all_iface_msgs.items() + if v["category"].lower() == args.category.lower() + } + else: + iface_msgs = all_iface_msgs + + iface_keys = set(iface_msgs.keys()) + all_iface_keys = set(all_iface_msgs.keys()) + scicall_keys = set(scicall_wrappers.keys()) + + unwrapped = sorted(iface_keys - scicall_keys, key=lambda k: iface_msgs[k]["num"]) + # Stale check always uses the full iface (not filtered) + stale = sorted(scicall_keys - all_iface_keys) + wrapped = sorted(iface_keys & scicall_keys, key=lambda k: iface_msgs[k]["num"]) + + # Generate mode: output DeclareSciCall* lines grouped by category + if args.generate: + non_deprecated = [ + k for k in unwrapped if iface_msgs[k]["category"] != "Deprecated" + ] + by_cat = {} + for key in non_deprecated: + cat = iface_msgs[key]["category"] + by_cat.setdefault(cat, []).append(key) + + for cat in sorted(by_cat.keys()): + keys = by_cat[cat] + print(f"// --- [{cat}] ({len(keys)} wrappers) ---") + for key in keys: + msg = iface_msgs[key] + line = generate_wrapper(msg) + print(line) + print() + print(f"// Total: {len(non_deprecated)} generated wrappers") + return 0 + + # Group unwrapped by category + unwrapped_by_cat = {} + for key in unwrapped: + cat = iface_msgs[key]["category"] + unwrapped_by_cat.setdefault(cat, []).append(key) + + # Summary + cat_label = f" (category: {args.category})" if args.category else "" + print(f"=== SciCall.h Coverage Report{cat_label} ===") + print(f" iface messages (fun/get/set): {len(iface_msgs)}") + print(f" SciCall.h wrappers: {len(scicall_wrappers)}") + print(f" Wrapped (matched): {len(wrapped)}") + print(f" Unwrapped (missing): {len(unwrapped)}") + print(f" Stale/custom (no iface): {len(stale)}") + print() + + # Unwrapped messages + if unwrapped: + print(f"--- Unwrapped iface messages ({len(unwrapped)}) ---") + for cat in sorted(unwrapped_by_cat.keys()): + keys = unwrapped_by_cat[cat] + print(f"\n [{cat}] ({len(keys)} messages)") + for key in keys: + msg = iface_msgs[key] + if args.verbose: + print(f" SCI_{key} = {msg['num']}") + print(f" {msg['type']} {msg['ret']} {msg['name']}({msg['params']})") + print(f" iface line {msg['line']}") + else: + print(f" SCI_{key:<45s} {msg['type']:<4s} {msg['ret']:<16s} {msg['name']}({msg['params']})") + print() + + # Stale wrappers (in SciCall.h but not in iface) + if stale: + print(f"--- Stale/custom wrappers ({len(stale)}) ---") + print(" (In SciCall.h but no matching iface fun/get/set)") + for key in stale: + w = scicall_wrappers[key] + status = " [commented]" if w["commented"] else "" + print(f" SCI_{key:<45s} SciCall_{w['fn']:<30s} line {w['line']}{status}") + print() + + # Wrapped messages (optional) + if args.show_wrapped and wrapped: + print(f"--- Wrapped messages ({len(wrapped)}) ---") + for key in wrapped: + msg = iface_msgs[key] + w = scicall_wrappers[key] + status = " [commented]" if w["commented"] else "" + print(f" SCI_{key:<45s} -> SciCall_{w['fn']}{status}") + print() + + # Exit code: 0 if no unwrapped non-deprecated messages, 1 otherwise + non_deprecated_unwrapped = [ + k for k in unwrapped if iface_msgs[k]["category"] != "Deprecated" + ] + if non_deprecated_unwrapped: + print(f"({len(non_deprecated_unwrapped)} unwrapped non-deprecated messages)") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/Edit.c b/src/Edit.c index 08d75d128..6180c5a4c 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -5533,23 +5533,23 @@ void EditSortLines(HWND hwnd, int iSortFlags) if (iSortFlags & SORT_ASCENDING) { if (iSortFlags & SORT_NOCASE) { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdI); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdI); } else if (iSortFlags & SORT_LOGICAL) { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogical); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogical); } else if (iSortFlags & SORT_LEXICOGRAPH) { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographical); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographical); } else { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStd); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStd); } } else if (iSortFlags & SORT_DESCENDING) { if (iSortFlags & SORT_NOCASE) { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdIRev); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdIRev); } else if (iSortFlags & SORT_LOGICAL) { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogicalRev); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogicalRev); } else if (iSortFlags & SORT_LEXICOGRAPH) { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographicalRev); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographicalRev); } else { - qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdRev); + NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdRev); } } else { /*if (iSortFlags & SORT_SHUFFLE)*/ srand((UINT)GetTicks_ms()); @@ -8372,7 +8372,7 @@ bool EditAutoCompleteWord(HWND hwnd, bool autoInsert) SciCall_AutoCSetChooseSingle(autoInsert); const char* const sep = " "; - SciCall_AutoCSetSeperator(sep[0]); + SciCall_AutoCSetSeparator(sep[0]); ++iWListSize; // zero termination char* const pList = AllocMem(iWListSize + 1, HEAP_ZERO_MEMORY); diff --git a/src/Encoding.c b/src/Encoding.c index 67b1d1e9f..761c62500 100644 --- a/src/Encoding.c +++ b/src/Encoding.c @@ -372,7 +372,7 @@ void Encoding_AddToListView(HWND hwnd, cpi_enc_t idSel, bool bRecodeOnly) pEE[i].id = i; GetLngString(g_Encodings[i].idsName, pEE[i].wch, COUNTOF(pEE[i].wch)); } - qsort(pEE, Encoding_CountOf(), sizeof(ENCODINGENTRY), CmpEncoding); + NP3_SORT(pEE, Encoding_CountOf(), sizeof(ENCODINGENTRY), CmpEncoding); LVITEM lvi = { 0 }; lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE; @@ -458,7 +458,7 @@ void Encoding_AddToComboboxEx(HWND hwnd, cpi_enc_t idSel, bool bRecodeOnly) pEE[i].id = i; GetLngString(g_Encodings[i].idsName, pEE[i].wch, COUNTOF(pEE[i].wch)); } - qsort(pEE, Encoding_CountOf(), sizeof(ENCODINGENTRY), CmpEncoding); + NP3_SORT(pEE, Encoding_CountOf(), sizeof(ENCODINGENTRY), CmpEncoding); COMBOBOXEXITEM cbei = { 0 }; cbei.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_LPARAM; diff --git a/src/Helpers.c b/src/Helpers.c index df886b9d7..82496437e 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -2074,7 +2074,7 @@ size_t ReadVectorFromString(LPCWSTR wchStrg, int iVector[], size_t iCount, int i } if (ordered) { - qsort(iVector, n, sizeof(int), _cmpifunc); + NP3_SORT(iVector, n, sizeof(int), _cmpifunc); } return n; diff --git a/src/Helpers.h b/src/Helpers.h index 99a680787..9fbb4eb61 100644 --- a/src/Helpers.h +++ b/src/Helpers.h @@ -27,6 +27,8 @@ #include "Scintilla.h" +#include "timsort/timsort.h" + // ============================================================================ // --- Disable/Enable some CodeAnalysis Warnings --- @@ -54,6 +56,9 @@ #define NOOP ((void)0) +//~#define NP3_SORT qsort // not stable, O(n log n) worst-case performance, but O(n) best-case performance for already sorted data +#define NP3_SORT timsort // stable, adaptive, iterative mergesort with O(n log n) worst-case and O(n) best-case performance + // ============================================================================ // direct heap allocation @@ -851,7 +856,7 @@ int Hex2Char(char* ch, int cnt); size_t SimpleHash(LPCWSTR string); - void CloseNonModalDialogs(); +void CloseNonModalDialogs(); void CloseApplication(); // ---------------------------------------------------------------------------- diff --git a/src/Notepad3.vcxproj b/src/Notepad3.vcxproj index 5aedbf09c..09cd4a35d 100644 --- a/src/Notepad3.vcxproj +++ b/src/Notepad3.vcxproj @@ -988,6 +988,8 @@ + + @@ -1131,6 +1133,8 @@ + + diff --git a/src/Notepad3.vcxproj.filters b/src/Notepad3.vcxproj.filters index e791fa828..a028e5e9f 100644 --- a/src/Notepad3.vcxproj.filters +++ b/src/Notepad3.vcxproj.filters @@ -46,6 +46,9 @@ {60486982-91be-42d2-b154-86c2706ca60f} + + {9a2064fb-b044-4ce5-91de-99fa06cc5222} + @@ -432,6 +435,12 @@ Source Files\StyleLexers + + timsort + + + timsort + @@ -611,6 +620,12 @@ Source Files\tinyexpr + + timsort + + + timsort + diff --git a/src/SciCall.h b/src/SciCall.h index 5f2a5b3d2..b6b0f9f0a 100644 --- a/src/SciCall.h +++ b/src/SciCall.h @@ -163,8 +163,11 @@ DeclareSciCallR0(GetTechnology, GETTECHNOLOGY, int); DeclareSciCallV1(SetTechnology, SETTECHNOLOGY, int, technology); DeclareSciCallR0(GetBidirectional, GETBIDIRECTIONAL, int); DeclareSciCallV1(SetBidirectional, SETBIDIRECTIONAL, int, direction); +DeclareSciCallR0(GetBufferedDraw, GETBUFFEREDDRAW, bool); DeclareSciCallV1(SetBufferedDraw, SETBUFFEREDDRAW, bool, value); +DeclareSciCallR0(GetPhasesDraw, GETPHASESDRAW, int); DeclareSciCallV1(SetPhasesDraw, SETPHASESDRAW, int, phases); +DeclareSciCallR0(GetCharacterCategoryOptimization, GETCHARACTERCATEGORYOPTIMIZATION, int); DeclareSciCallV1(SetCharacterCategoryOptimization, SETCHARACTERCATEGORYOPTIMIZATION, int, count); DeclareSciCallR1(SupportsFeature, SUPPORTSFEATURE, bool, int, feature); // Layout, Position Cache and Layout Threads @@ -178,30 +181,49 @@ DeclareSciCallV1(SetLayoutThreads, SETLAYOUTTHREADS, int, threads); // Event Masks DeclareSciCallR0(GetModEventMask, GETMODEVENTMASK, int); DeclareSciCallV1(SetModEventMask, SETMODEVENTMASK, int, mask); +DeclareSciCallR0(GetCommandEvents, GETCOMMANDEVENTS, bool); DeclareSciCallV1(SetCommandEvents, SETCOMMANDEVENTS, bool, flag); // Code Page +DeclareSciCallR0(GetCodePage, GETCODEPAGE, int); DeclareSciCallV1(SetCodePage, SETCODEPAGE, int, cp); DeclareSciCallV1(StyleSetCharacterSet, STYLESETCHARACTERSET, int, cs); // Divers +DeclareSciCallR0(GetMargins, GETMARGINS, int); DeclareSciCallV1(SetMargins, SETMARGINS, int, nmarg); DeclareSciCallV1(SetPasteConvertEndings, SETPASTECONVERTENDINGS, bool, flag); DeclareSciCallV1(UsePopUp, USEPOPUP, int, option); // Multi Selection DeclareSciCallR0(GetMultipleSelection, GETMULTIPLESELECTION, bool); DeclareSciCallV1(SetMultipleSelection, SETMULTIPLESELECTION, bool, flag); +DeclareSciCallR0(GetMultiPaste, GETMULTIPASTE, int); DeclareSciCallV1(SetMultiPaste, SETMULTIPASTE, int, option); DeclareSciCallR0(GetAdditionalSelectionTyping, GETADDITIONALSELECTIONTYPING, bool); DeclareSciCallV1(SetAdditionalSelectionTyping, SETADDITIONALSELECTIONTYPING, bool, flag); +DeclareSciCallR0(GetMouseSelectionRectangularSwitch, GETMOUSESELECTIONRECTANGULARSWITCH, bool); DeclareSciCallV1(SetMouseSelectionRectangularSwitch, SETMOUSESELECTIONRECTANGULARSWITCH, bool, flag); +// Caret Line +DeclareSciCallR0(GetCaretLineVisible, GETCARETLINEVISIBLE, bool); +DeclareSciCallV1(SetCaretLineVisible, SETCARETLINEVISIBLE, bool, show); +DeclareSciCallR0(GetCaretLineBack, GETCARETLINEBACK, COLORREF); +DeclareSciCallV1(SetCaretLineBack, SETCARETLINEBACK, COLORREF, back); +DeclareSciCallR0(GetCaretLineBackAlpha, GETCARETLINEBACKALPHA, int); +DeclareSciCallV1(SetCaretLineBackAlpha, SETCARETLINEBACKALPHA, int, alpha); +DeclareSciCallR0(GetCaretLineLayer, GETCARETLINELAYER, int); DeclareSciCallV1(SetCaretLineLayer, SETCARETLINELAYER, int, layer); DeclareSciCallR0(GetCaretLineFrame, GETCARETLINEFRAME, int); DeclareSciCallV1(SetCaretLineFrame, SETCARETLINEFRAME, int, frm); +DeclareSciCallR0(GetCaretLineVisibleAlways, GETCARETLINEVISIBLEALWAYS, bool); DeclareSciCallV1(SetCaretLineVisibleAlways, SETCARETLINEVISIBLEALWAYS, bool, flag); +DeclareSciCallR0(GetCaretLineHighlightSubLine, GETCARETLINEHIGHLIGHTSUBLINE, bool); +DeclareSciCallV1(SetCaretLineHighlightSubLine, SETCARETLINEHIGHLIGHTSUBLINE, bool, subLine); +DeclareSciCallR0(GetAutomaticFold, GETAUTOMATICFOLD, int); DeclareSciCallV1(SetAutomaticFold, SETAUTOMATICFOLD, int, option); +DeclareSciCallR0(GetCaretSticky, GETCARETSTICKY, int); DeclareSciCallV1(SetCaretSticky, SETCARETSTICKY, int, option); +DeclareSciCallV0(ToggleCaretSticky, TOGGLECARETSTICKY); DeclareSciCallV2(SetXCaretPolicy, SETXCARETPOLICY, int, policy, int, slop); DeclareSciCallV2(SetYCaretPolicy, SETYCARETPOLICY, int, policy, int, slop); @@ -210,9 +232,38 @@ DeclareSciCallV01(GetWhiteSpaceChars, GETWHITESPACECHARS, char*, ptxt); DeclareSciCallV01(GetPunctuationChars, GETPUNCTUATIONCHARS, char*, ptxt); DeclareSciCallV2(SetRepresentation, SETREPRESENTATION, const char*, encChar, const char*, represent); -DeclareSciCallV2(SetRepresentationColour, SETREPRESENTATIONCOLOUR, const char*, encChar, COLORALPHAREF, colour); -DeclareSciCallV2(SetRepresentationAppearance, SETREPRESENTATIONAPPEARANCE, const char*, encChar, int, appear); +DeclareSciCallR2(GetRepresentation, GETREPRESENTATION, int, const char*, encodedCharacter, char*, representation); +DeclareSciCallV1(ClearRepresentation, CLEARREPRESENTATION, const char*, encodedCharacter); DeclareSciCallV0(ClearAllRepresentations, CLEARALLREPRESENTATIONS); +DeclareSciCallV2(SetRepresentationAppearance, SETREPRESENTATIONAPPEARANCE, const char*, encChar, int, appear); +DeclareSciCallR1(GetRepresentationAppearance, GETREPRESENTATIONAPPEARANCE, int, const char*, encodedCharacter); +DeclareSciCallV2(SetRepresentationColour, SETREPRESENTATIONCOLOUR, const char*, encChar, COLORALPHAREF, colour); +DeclareSciCallR1(GetRepresentationColour, GETREPRESENTATIONCOLOUR, COLORALPHAREF, const char*, encodedCharacter); +// Line End Types +DeclareSciCallV1(SetLineEndTypesAllowed, SETLINEENDTYPESALLOWED, int, lineEndBitSet); +DeclareSciCallR0(GetLineEndTypesAllowed, GETLINEENDTYPESALLOWED, int); +DeclareSciCallR0(GetLineEndTypesActive, GETLINEENDTYPESACTIVE, int); +// Tab Draw Mode +DeclareSciCallR0(GetTabDrawMode, GETTABDRAWMODE, int); +DeclareSciCallV1(SetTabDrawMode, SETTABDRAWMODE, int, tabDrawMode); +// Tab Minimum Width +DeclareSciCallV1(SetTabMinimumWidth, SETTABMINIMUMWIDTH, int, pixels); +DeclareSciCallR0(GetTabMinimumWidth, GETTABMINIMUMWIDTH, int); +// Accessibility +DeclareSciCallV1(SetAccessibility, SETACCESSIBILITY, int, accessibility); +DeclareSciCallR0(GetAccessibility, GETACCESSIBILITY, int); +// Identifier +DeclareSciCallV1(SetIdentifier, SETIDENTIFIER, int, identifier); +DeclareSciCallR0(GetIdentifier, GETIDENTIFIER, int); +// Font +DeclareSciCallR0(GetFontQuality, GETFONTQUALITY, int); +DeclareSciCallR01(GetFontLocale, GETFONTLOCALE, int, char*, localeName); +// Direct Function Pointers +DeclareSciCallR0(GetDirectFunction, GETDIRECTFUNCTION, sptr_t); +DeclareSciCallR0(GetDirectStatusFunction, GETDIRECTSTATUSFUNCTION, sptr_t); +// Allocation +DeclareSciCallV1(AllocateLines, ALLOCATELINES, DocLn, lines); +DeclareSciCallV1(Allocate, ALLOCATE, DocPos, bytes); // Document Pointer Handling DeclareSciCallR0(GetDocPointer, GETDOCPOINTER, sptr_t); @@ -242,9 +293,21 @@ DeclareSciCallV0(GrabFocus, GRABFOCUS); DeclareSciCallV1(SetFocus, SETFOCUS, bool, flag); DeclareSciCallR0(GetFocus, GETFOCUS, bool); DeclareSciCallR0(GetPasteConvertEndings, GETPASTECONVERTENDINGS, bool); +DeclareSciCallV1(SetOvertype, SETOVERTYPE, bool, overType); DeclareSciCallR0(GetOverType, GETOVERTYPE, bool); DeclareSciCallR0(GetReadOnly, GETREADONLY, bool); DeclareSciCallV1(SetReadOnly, SETREADONLY, bool, flag); +DeclareSciCallR0(GetSelectionHidden, GETSELECTIONHIDDEN, bool); +DeclareSciCallV1(HideSelection, HIDESELECTION, bool, hide); +DeclareSciCallV1(SetStatus, SETSTATUS, int, status); +DeclareSciCallR0(GetStatus, GETSTATUS, int); +DeclareSciCallV1(SetMouseDownCaptures, SETMOUSEDOWNCAPTURES, bool, captures); +DeclareSciCallR0(GetMouseDownCaptures, GETMOUSEDOWNCAPTURES, bool); +DeclareSciCallV1(SetMouseWheelCaptures, SETMOUSEWHEELCAPTURES, bool, captures); +DeclareSciCallR0(GetMouseWheelCaptures, GETMOUSEWHEELCAPTURES, bool); +DeclareSciCallR0(GetCursor, GETCURSOR, int); +DeclareSciCallV1(SetControlCharSymbol, SETCONTROLCHARSYMBOL, int, symbol); +DeclareSciCallR0(GetControlCharSymbol, GETCONTROLCHARSYMBOL, int); DeclareSciCallV1(SetSelectionLayer, SETSELECTIONLAYER, int, layer); DeclareSciCallR0(GetSelectionLayer, GETSELECTIONLAYER, int); @@ -267,8 +330,30 @@ DeclareSciCallR01(PointYFromPosition, POINTYFROMPOSITION, int, DocPos, position) DeclareSciCallR2(WordStartPosition, WORDSTARTPOSITION, DocPos, DocPos, pos, bool, onlyWordChars); DeclareSciCallR2(WordEndPosition, WORDENDPOSITION, DocPos, DocPos, pos, bool, onlyWordChars); +// Selection colors +DeclareSciCallV2(SetSelFore, SETSELFORE, bool, useSetting, COLORREF, fore); +DeclareSciCallV2(SetSelBack, SETSELBACK, bool, useSetting, COLORREF, back); +DeclareSciCallR0(GetSelAlpha, GETSELALPHA, int); +DeclareSciCallV1(SetSelAlpha, SETSELALPHA, int, alpha); +DeclareSciCallR0(GetSelEOLFilled, GETSELEOLFILLED, bool); +DeclareSciCallV1(SetAdditionalSelFore, SETADDITIONALSELFORE, COLORREF, fore); +DeclareSciCallV1(SetAdditionalSelBack, SETADDITIONALSELBACK, COLORREF, back); +DeclareSciCallV1(SetAdditionalSelAlpha, SETADDITIONALSELALPHA, int, alpha); +DeclareSciCallR0(GetAdditionalSelAlpha, GETADDITIONALSELALPHA, int); +DeclareSciCallV1(SetAdditionalCaretFore, SETADDITIONALCARETFORE, COLORREF, fore); +DeclareSciCallR0(GetAdditionalCaretFore, GETADDITIONALCARETFORE, COLORREF); +DeclareSciCallR0(GetAdditionalCaretsBlink, GETADDITIONALCARETSBLINK, bool); +DeclareSciCallR0(GetAdditionalCaretsVisible, GETADDITIONALCARETSVISIBLE, bool); +DeclareSciCallV2(SetWhitespaceFore, SETWHITESPACEFORE, bool, useSetting, COLORREF, fore); +DeclareSciCallV2(SetWhitespaceBack, SETWHITESPACEBACK, bool, useSetting, COLORREF, back); +DeclareSciCallV1(SetCaretFore, SETCARETFORE, COLORREF, fore); +DeclareSciCallR0(GetCaretFore, GETCARETFORE, COLORREF); + // Rectangular selection with virtual space +DeclareSciCallR0(GetVirtualSpaceOptions, GETVIRTUALSPACEOPTIONS, int); DeclareSciCallV1(SetVirtualSpaceOptions, SETVIRTUALSPACEOPTIONS, int, options); +DeclareSciCallV1(SetRectangularSelectionModifier, SETRECTANGULARSELECTIONMODIFIER, int, modifier); +DeclareSciCallR0(GetRectangularSelectionModifier, GETRECTANGULARSELECTIONMODIFIER, int); DeclareSciCallR0(GetRectangularSelectionCaret, GETRECTANGULARSELECTIONCARET, DocPos); DeclareSciCallV1(SetRectangularSelectionCaret, SETRECTANGULARSELECTIONCARET, DocPos, position); DeclareSciCallR0(GetRectangularSelectionAnchor, GETRECTANGULARSELECTIONANCHOR, DocPos); @@ -284,7 +369,6 @@ DeclareSciCallR0(GetSelectionMode, GETSELECTIONMODE, int); DeclareSciCallV1(SetSelectionMode, SETSELECTIONMODE, int, mode); DeclareSciCallV1(ChangeSelectionMode, CHANGESELECTIONMODE, int, mode); DeclareSciCallR0(GetSelections, GETSELECTIONS, DocPosU); -DeclareSciCallR0(GetSelectionEmpty, GETSELECTIONS, bool); DeclareSciCallV2(SetSelection, SETSELECTION, DocPos, caretPos, DocPos, anchorPos); DeclareSciCallV1(SetSelectionStart, SETSELECTIONSTART, DocPos, anchorPos); DeclareSciCallV1(SetSelectionEnd, SETSELECTIONEND, DocPos, caretPos); @@ -302,10 +386,19 @@ DeclareSciCallV2(SetSelectionNAnchorVirtualSpace, SETSELECTIONNANCHORVIRTUALSPAC DeclareSciCallR1(GetSelectionNStart, GETSELECTIONNSTART, DocPos, DocPosU, selnum); DeclareSciCallR1(GetSelectionNEnd, GETSELECTIONNEND, DocPos, DocPosU, selnum); DeclareSciCallR1(GetSelectionNStartVirtualSpace, GETSELECTIONNSTARTVIRTUALSPACE, DocPos, DocPosU, selnum); +DeclareSciCallV2(SetSelectionNStart, SETSELECTIONNSTART, int, selection, DocPos, anchor); +DeclareSciCallV2(SetSelectionNEnd, SETSELECTIONNEND, int, selection, DocPos, caret); DeclareSciCallR1(GetSelectionNEndVirtualSpace, GETSELECTIONNENDVIRTUALSPACE, DocPos, DocPosU, selnum); +DeclareSciCallV1(DropSelectionN, DROPSELECTIONN, int, selection); +DeclareSciCallV1(SetMoveExtendsSelection, SETMOVEEXTENDSSELECTION, bool, moveExtendsSelection); DeclareSciCallR0(GetMoveExtendsSelection, GETMOVEEXTENDSSELECTION, bool); +DeclareSciCallR2(SelectionFromPoint, SELECTIONFROMPOINT, int, int, x, int, y); +// Serialized selection +DeclareSciCallV01(SetSelectionSerialized, SETSELECTIONSERIALIZED, const char*, selectionString); +DeclareSciCallR01(GetSelectionSerialized, GETSELECTIONSERIALIZED, DocPos, char*, selectionString); DeclareSciCallV0(SwapMainAnchorCaret, SWAPMAINANCHORCARET); +DeclareSciCallV0(MultipleSelectAddNext, MULTIPLESELECTADDNEXT); DeclareSciCallV0(MultipleSelectAddEach, MULTIPLESELECTADDEACH); DeclareSciCallV0(RotateSelection, ROTATESELECTION); @@ -320,40 +413,96 @@ DeclareSciCallV0(ZoomOut, ZOOMOUT); // while the SCI_VCHOME* commands move the caret to the first non-blank character of the line // (ie. just after the indentation) unless it is already there; in this case, it acts as SCI_HOME*. DeclareSciCallV0(Home, HOME); +DeclareSciCallV0(HomeExtend, HOMEEXTEND); DeclareSciCallV0(VCHome, VCHOME); +DeclareSciCallV0(VCHomeExtend, VCHOMEEXTEND); +DeclareSciCallV0(VCHomeWrap, VCHOMEWRAP); +DeclareSciCallV0(VCHomeWrapExtend, VCHOMEWRAPEXTEND); +DeclareSciCallV0(VCHomeDisplay, VCHOMEDISPLAY); +DeclareSciCallV0(VCHomeDisplayExtend, VCHOMEDISPLAYEXTEND); +DeclareSciCallV0(LineEnd, LINEEND); +DeclareSciCallV0(LineEndExtend, LINEENDEXTEND); +DeclareSciCallV0(LineEndWrap, LINEENDWRAP); +DeclareSciCallV0(LineEndWrapExtend, LINEENDWRAPEXTEND); +DeclareSciCallV0(LineEndDisplay, LINEENDDISPLAY); +DeclareSciCallV0(LineEndDisplayExtend, LINEENDDISPLAYEXTEND); +DeclareSciCallV0(HomeDisplay, HOMEDISPLAY); +DeclareSciCallV0(HomeDisplayExtend, HOMEDISPLAYEXTEND); +DeclareSciCallV0(HomeWrap, HOMEWRAP); +DeclareSciCallV0(HomeWrapExtend, HOMEWRAPEXTEND); DeclareSciCallV0(NewLine, NEWLINE); +DeclareSciCallV0(FormFeed, FORMFEED); DeclareSciCallV0(Tab, TAB); DeclareSciCallV0(BackTab, BACKTAB); DeclareSciCallV0(LineIndent, LINEINDENT); DeclareSciCallV0(LineDedent, LINEDEDENT); DeclareSciCallV0(LineUp, LINEUP); -DeclareSciCallV0(LineDown, LINEDOWN); DeclareSciCallV0(LineUpExtend, LINEUPEXTEND); -DeclareSciCallV0(LineScrollUp, LINESCROLLUP); +DeclareSciCallV0(LineDown, LINEDOWN); DeclareSciCallV0(LineDownExtend, LINEDOWNEXTEND); +DeclareSciCallV0(LineScrollUp, LINESCROLLUP); DeclareSciCallV0(LineScrollDown, LINESCROLLDOWN); DeclareSciCallV0(CharLeft, CHARLEFT); DeclareSciCallV0(CharLeftExtend, CHARLEFTEXTEND); DeclareSciCallV0(CharRight, CHARRIGHT); DeclareSciCallV0(CharRightExtend, CHARRIGHTEXTEND); DeclareSciCallV0(WordLeft, WORDLEFT); +DeclareSciCallV0(WordLeftExtend, WORDLEFTEXTEND); DeclareSciCallV0(WordRight, WORDRIGHT); +DeclareSciCallV0(WordRightExtend, WORDRIGHTEXTEND); +DeclareSciCallV0(WordPartLeft, WORDPARTLEFT); +DeclareSciCallV0(WordPartLeftExtend, WORDPARTLEFTEXTEND); +DeclareSciCallV0(WordPartRight, WORDPARTRIGHT); +DeclareSciCallV0(WordPartRightExtend, WORDPARTRIGHTEXTEND); +DeclareSciCallV0(WordLeftEnd, WORDLEFTEND); +DeclareSciCallV0(WordLeftEndExtend, WORDLEFTENDEXTEND); +DeclareSciCallV0(WordRightEnd, WORDRIGHTEND); +DeclareSciCallV0(WordRightEndExtend, WORDRIGHTENDEXTEND); +DeclareSciCallV0(DocumentStart, DOCUMENTSTART); +DeclareSciCallV0(DocumentStartExtend, DOCUMENTSTARTEXTEND); +DeclareSciCallV0(DocumentEnd, DOCUMENTEND); +DeclareSciCallV0(DocumentEndExtend, DOCUMENTENDEXTEND); +DeclareSciCallV0(PageUp, PAGEUP); +DeclareSciCallV0(PageUpExtend, PAGEUPEXTEND); +DeclareSciCallV0(PageDown, PAGEDOWN); +DeclareSciCallV0(PageDownExtend, PAGEDOWNEXTEND); +DeclareSciCallV0(StutteredPageUp, STUTTEREDPAGEUP); +DeclareSciCallV0(StutteredPageUpExtend, STUTTEREDPAGEUPEXTEND); +DeclareSciCallV0(StutteredPageDown, STUTTEREDPAGEDOWN); +DeclareSciCallV0(StutteredPageDownExtend, STUTTEREDPAGEDOWNEXTEND); DeclareSciCallV0(ParaUp, PARAUP); DeclareSciCallV0(ParaUpExtend, PARAUPEXTEND); DeclareSciCallV0(ParaDown, PARADOWN); DeclareSciCallV0(ParaDownExtend, PARADOWNEXTEND); +// Rectangular extension +DeclareSciCallV0(LineDownRectExtend, LINEDOWNRECTEXTEND); +DeclareSciCallV0(LineUpRectExtend, LINEUPRECTEXTEND); +DeclareSciCallV0(CharLeftRectExtend, CHARLEFTRECTEXTEND); +DeclareSciCallV0(CharRightRectExtend, CHARRIGHTRECTEXTEND); +DeclareSciCallV0(HomeRectExtend, HOMERECTEXTEND); +DeclareSciCallV0(VCHomeRectExtend, VCHOMERECTEXTEND); +DeclareSciCallV0(LineEndRectExtend, LINEENDRECTEXTEND); +DeclareSciCallV0(PageUpRectExtend, PAGEUPRECTEXTEND); +DeclareSciCallV0(PageDownRectExtend, PAGEDOWNRECTEXTEND); +// Delete and line operations DeclareSciCallV0(DeleteBack, DELETEBACK); +DeclareSciCallV0(DeleteBackNotLine, DELETEBACKNOTLINE); DeclareSciCallV0(DelWordLeft, DELWORDLEFT); DeclareSciCallV0(DelWordRight, DELWORDRIGHT); +DeclareSciCallV0(DelWordRightEnd, DELWORDRIGHTEND); DeclareSciCallV0(DelLineLeft, DELLINELEFT); DeclareSciCallV0(DelLineRight, DELLINERIGHT); DeclareSciCallV0(LineDelete, LINEDELETE); DeclareSciCallV0(LineCut, LINECUT); +DeclareSciCallV0(LineCopy, LINECOPY); +DeclareSciCallV0(LineReverse, LINEREVERSE); DeclareSciCallV1(LinesSplit, LINESSPLIT, int, pix); DeclareSciCallV0(LinesJoin, LINESJOIN); DeclareSciCallV0(EditToggleOverType, EDITTOGGLEOVERTYPE); DeclareSciCallV2(AssignCmdKey, ASSIGNCMDKEY, size_t, key, unsigned, cmd); +DeclareSciCallV1(ClearCmdKey, CLEARCMDKEY, size_t, keyDefinition); +DeclareSciCallV0(ClearAllCmdKeys, CLEARALLCMDKEYS); // Commands DeclareSciCallV0(LineDuplicate, LINEDUPLICATE); @@ -361,7 +510,12 @@ DeclareSciCallV0(SelectionDuplicate, SELECTIONDUPLICATE); DeclareSciCallV0(LineTranspose, LINETRANSPOSE); DeclareSciCallV0(MoveSelectedLinesUp, MOVESELECTEDLINESUP); DeclareSciCallV0(MoveSelectedLinesDown, MOVESELECTEDLINESDOWN); +DeclareSciCallV0(CutAllowLine, CUTALLOWLINE); +DeclareSciCallR2(FindText, FINDTEXT, DocPos, int, searchFlags, struct Sci_TextToFind*, ft); DeclareSciCallR2(FindTextFull, FINDTEXTFULL, DocPos, int, flags, struct Sci_TextToFindFull*, text); +DeclareSciCallV0(SearchAnchor, SEARCHANCHOR); +DeclareSciCallR2(SearchNext, SEARCHNEXT, DocPos, int, searchFlags, const char*, text); +DeclareSciCallR2(SearchPrev, SEARCHPREV, DocPos, int, searchFlags, const char*, text); // Operations DeclareSciCallV0(Cut, CUT); @@ -373,13 +527,45 @@ DeclareSciCallV2(CopyRange, COPYRANGE, DocPos, start, DocPos, end); DeclareSciCallV0(Cancel, CANCEL); DeclareSciCallV0(CopyAllowLine, COPYALLOWLINE); DeclareSciCallV2(CopyText, COPYTEXT, DocPos, length, const char*, text); +DeclareSciCallV2(AddStyledText, ADDSTYLEDTEXT, DocPos, length, const char*, c); +DeclareSciCallR0(GetLength, GETLENGTH, DocPos); +DeclareSciCallR1(GetStyleAt, GETSTYLEAT, int, DocPos, pos); +DeclareSciCallR01(GetStyledText, GETSTYLEDTEXT, DocPos, struct Sci_TextRange*, tr); +DeclareSciCallR01(GetStyledTextFull, GETSTYLEDTEXTFULL, DocPos, struct Sci_TextRangeFull*, tr); +DeclareSciCallR01(GetTextRange, GETTEXTRANGE, DocPos, struct Sci_TextRange*, tr); DeclareSciCallR2(GetText, GETTEXT, DocPos, DocPos, length, const char*, text); // NULL: w/o terminating '\0' (SCI v515) DeclareSciCallR01(GetTextRangeFull, GETTEXTRANGEFULL, DocPos, struct Sci_TextRangeFull*, textrange); +DeclareSciCallV01(SetText, SETTEXT, const char*, text); +DeclareSciCallV0(Null, NULL); DeclareSciCallV0(UpperCase, UPPERCASE); DeclareSciCallV0(LowerCase, LOWERCASE); DeclareSciCallV2(ReplaceRectangular, REPLACERECTANGULAR, DocPos, length, const char *, text); DeclareSciCallV01(SetCopySeparator, SETCOPYSEPARATOR, const char*, sep); - +DeclareSciCallR01(GetCopySeparator, GETCOPYSEPARATOR, int, char*, separator); +DeclareSciCallV2(SetStylingEx, SETSTYLINGEX, DocPos, length, const char*, styles); +DeclareSciCallR0(GetSearchFlags, GETSEARCHFLAGS, int); +DeclareSciCallV1(SetTargetStart, SETTARGETSTART, DocPos, start); +DeclareSciCallV1(SetTargetEnd, SETTARGETEND, DocPos, end); +DeclareSciCallV1(SetTargetStartVirtualSpace, SETTARGETSTARTVIRTUALSPACE, DocPos, space); +DeclareSciCallR0(GetTargetStartVirtualSpace, GETTARGETSTARTVIRTUALSPACE, DocPos); +DeclareSciCallV1(SetTargetEndVirtualSpace, SETTARGETENDVIRTUALSPACE, DocPos, space); +DeclareSciCallR0(GetTargetEndVirtualSpace, GETTARGETENDVIRTUALSPACE, DocPos); +DeclareSciCallR2(IsRangeWord, ISRANGEWORD, bool, DocPos, start, DocPos, end); +DeclareSciCallR2(CountCodeUnits, COUNTCODEUNITS, DocPos, DocPos, start, DocPos, end); +DeclareSciCallR2(PositionRelativeCodeUnits, POSITIONRELATIVECODEUNITS, DocPos, DocPos, pos, DocPos, relative); +DeclareSciCallR1(TextHeight, TEXTHEIGHT, int, DocLn, line); +DeclareSciCallR2(GetTag, GETTAG, int, int, tagNumber, char*, tagValue); +DeclareSciCallR2(ChangeLexerState, CHANGELEXERSTATE, int, DocPos, start, DocPos, end); +DeclareSciCallR0(GetGapPosition, GETGAPPOSITION, DocPos); +// Line Character Index +DeclareSciCallR0(GetLineCharacterIndex, GETLINECHARACTERINDEX, int); +DeclareSciCallV1(AllocateLineCharacterIndex, ALLOCATELINECHARACTERINDEX, int, lineCharacterIndex); +DeclareSciCallV1(ReleaseLineCharacterIndex, RELEASELINECHARACTERINDEX, int, lineCharacterIndex); +DeclareSciCallR2(LineFromIndexPosition, LINEFROMINDEXPOSITION, DocLn, DocPos, pos, int, lineCharacterIndex); +DeclareSciCallR2(IndexPositionFromLine, INDEXPOSITIONFROMLINE, DocPos, DocLn, line, int, lineCharacterIndex); +// Encoding +DeclareSciCallV1(SetLengthForEncode, SETLENGTHFORENCODE, DocPos, bytes); +DeclareSciCallR2(EncodedFromUTF8, ENCODEDFROMUTF8, DocPos, const char*, utf8, char*, encoded); //DeclareSciCallR01(TargetAsUTF8, TARGETASUTF8, DocPos, const char*, text); // WideCharToMultiByteEx(Encoding_SciCP); // SCI_ENCODEDFROMUTF8 - no need, internal CP is UTF8 always (fixed const for Notepad3); @@ -413,8 +599,6 @@ DeclareSciCallV1(SetCurrentPos, SETCURRENTPOS, DocPos, position); DeclareSciCallV1(GotoPos, GOTOPOS, DocPos, position); DeclareSciCallV1(GotoLine, GOTOLINE, DocLn, line); -DeclareSciCallV0(DocumentStart, DOCUMENTSTART); -DeclareSciCallV0(DocumentEnd, DOCUMENTEND); DeclareSciCallR1(PositionBefore, POSITIONBEFORE, DocPos, DocPos, position); DeclareSciCallR1(PositionAfter, POSITIONAFTER, DocPos, DocPos, position); DeclareSciCallR1(GetCharAt, GETCHARAT, char, DocPos, position); @@ -476,27 +660,62 @@ DeclareSciCallV1(CallTipSetForeHlt, CALLTIPSETFOREHLT, COLORREF, colour); DeclareSciCallV1(CallTipSetBack, CALLTIPSETBACK, COLORREF, colour); DeclareSciCallV1(CallTipSetPosition, CALLTIPSETPOSITION, bool, above); DeclareSciCallR0(CallTipPosStart, CALLTIPPOSSTART, DocPos); +DeclareSciCallV1(CallTipSetPosStart, CALLTIPSETPOSSTART, DocPos, posStart); DeclareSciCallV2(CallTipShow, CALLTIPSHOW, DocPos, position, const char*, text); DeclareSciCallV2(CallTipSetHlt, CALLTIPSETHLT, int, beg, int, end); DeclareSciCallR0(CallTipActive, CALLTIPACTIVE, bool); DeclareSciCallV0(CallTipCancel, CALLTIPCANCEL); DeclareSciCallV1(CallTipUseStyle, CALLTIPUSESTYLE, int, tabsize); DeclareSciCallV1(SetMouseDWellTime, SETMOUSEDWELLTIME, int, millisec); +DeclareSciCallR0(GetMouseDwellTime, GETMOUSEDWELLTIME, int); DeclareSciCallR0(AutoCActive, AUTOCACTIVE, bool); DeclareSciCallV0(AutoCComplete, AUTOCCOMPLETE); DeclareSciCallV0(AutoCCancel, AUTOCCANCEL); -DeclareSciCallV0(ClearRegisteredImages, CLEARREGISTEREDIMAGES); -DeclareSciCallV1(AutoCSetOptions, AUTOCSETOPTIONS, int, options); -DeclareSciCallV1(AutoCSetIgnoreCase, AUTOCSETIGNORECASE, bool, flag); -DeclareSciCallV1(AutoCSetCaseInsensitiveBehaviour, AUTOCSETCASEINSENSITIVEBEHAVIOUR, int, options); -DeclareSciCallV1(AutoCSetSeperator, AUTOCSETSEPARATOR, char, seperator); +DeclareSciCallR0(AutoCPosStart, AUTOCPOSSTART, DocPos); +DeclareSciCallV01(AutoCStops, AUTOCSTOPS, const char*, characterSet); +DeclareSciCallV1(AutoCSetSeparator, AUTOCSETSEPARATOR, char, separator); +DeclareSciCallR0(AutoCGetSeparator, AUTOCGETSEPARATOR, int); +DeclareSciCallV01(AutoCSelect, AUTOCSELECT, const char*, select); +DeclareSciCallV1(AutoCSetStyle, AUTOCSETSTYLE, int, style); +DeclareSciCallR0(AutoCGetStyle, AUTOCGETSTYLE, int); +DeclareSciCallV1(AutoCSetCancelAtStart, AUTOCSETCANCELATSTART, bool, cancel); +DeclareSciCallR0(AutoCGetCancelAtStart, AUTOCGETCANCELATSTART, bool); DeclareSciCallV01(AutoCSetFillups, AUTOCSETFILLUPS, const char*, text); DeclareSciCallV1(AutoCSetChooseSingle, AUTOCSETCHOOSESINGLE, bool, flag); +DeclareSciCallR0(AutoCGetChooseSingle, AUTOCGETCHOOSESINGLE, bool); +DeclareSciCallV1(AutoCSetIgnoreCase, AUTOCSETIGNORECASE, bool, flag); +DeclareSciCallR0(AutoCGetIgnoreCase, AUTOCGETIGNORECASE, bool); +DeclareSciCallV1(AutoCSetAutoHide, AUTOCSETAUTOHIDE, bool, autoHide); +DeclareSciCallR0(AutoCGetAutoHide, AUTOCGETAUTOHIDE, bool); +DeclareSciCallV1(AutoCSetDropRestOfWord, AUTOCSETDROPRESTOFWORD, bool, dropRestOfWord); +DeclareSciCallR0(AutoCGetDropRestOfWord, AUTOCGETDROPRESTOFWORD, bool); +DeclareSciCallV1(AutoCSetTypeSeparator, AUTOCSETTYPESEPARATOR, int, separatorCharacter); +DeclareSciCallR0(AutoCGetTypeSeparator, AUTOCGETTYPESEPARATOR, int); +DeclareSciCallV1(AutoCSetMaxWidth, AUTOCSETMAXWIDTH, int, characterCount); +DeclareSciCallR0(AutoCGetMaxWidth, AUTOCGETMAXWIDTH, int); +DeclareSciCallV1(AutoCSetMaxHeight, AUTOCSETMAXHEIGHT, int, rowCount); +DeclareSciCallR0(AutoCGetMaxHeight, AUTOCGETMAXHEIGHT, int); +DeclareSciCallV1(AutoCSetOptions, AUTOCSETOPTIONS, int, options); +DeclareSciCallR0(AutoCGetOptions, AUTOCGETOPTIONS, int); +DeclareSciCallV1(AutoCSetCaseInsensitiveBehaviour, AUTOCSETCASEINSENSITIVEBEHAVIOUR, int, options); +DeclareSciCallR0(AutoCGetCaseInsensitiveBehaviour, AUTOCGETCASEINSENSITIVEBEHAVIOUR, int); DeclareSciCallR0(AutoCGetOrder, AUTOCGETORDER, int); DeclareSciCallV1(AutoCSetOrder, AUTOCSETORDER, int, options); DeclareSciCallV1(AutoCSetMulti, AUTOCSETMULTI, int, options); +DeclareSciCallR0(AutoCGetMulti, AUTOCGETMULTI, int); +DeclareSciCallR0(AutoCGetCurrent, AUTOCGETCURRENT, int); +DeclareSciCallR01(AutoCGetCurrentText, AUTOCGETCURRENTTEXT, int, char*, text); +DeclareSciCallV1(AutoCSetImageScale, AUTOCSETIMAGESCALE, int, scalePercent); +DeclareSciCallR0(AutoCGetImageScale, AUTOCGETIMAGESCALE, int); DeclareSciCallV2(AutoCShow, AUTOCSHOW, DocPos, len, const char*, list); +DeclareSciCallV2(UserListShow, USERLISTSHOW, int, listType, const char*, itemList); +DeclareSciCallV2(RegisterImage, REGISTERIMAGE, int, type, const char*, xpmData); +DeclareSciCallV2(RegisterRGBAImage, REGISTERRGBAIMAGE, int, type, const char*, pixels); +DeclareSciCallV1(RGBAImageSetWidth, RGBAIMAGESETWIDTH, int, width); +DeclareSciCallV1(RGBAImageSetHeight, RGBAIMAGESETHEIGHT, int, height); +DeclareSciCallV1(RGBAImageSetScale, RGBAIMAGESETSCALE, int, scalePercent); +DeclareSciCallV0(ClearRegisteredImages, CLEARREGISTEREDIMAGES); //============================================================================= @@ -509,16 +728,22 @@ DeclareSciCallV0(ScrollCaret, SCROLLCARET); DeclareSciCallV0(ChooseCaretX, CHOOSECARETX); DeclareSciCallV2(LineScroll, LINESCROLL, DocPos, columns, DocLn, lines); DeclareSciCallV2(ScrollRange, SCROLLRANGE, DocPos, secondaryPos, DocPos, primaryPos); +DeclareSciCallR0(GetScrollWidth, GETSCROLLWIDTH, int); DeclareSciCallV1(SetScrollWidth, SETSCROLLWIDTH, int, width); +DeclareSciCallR0(GetScrollWidthTracking, GETSCROLLWIDTHTRACKING, bool); DeclareSciCallV1(SetScrollWidthTracking, SETSCROLLWIDTHTRACKING, bool, srwt); +DeclareSciCallR0(GetEndAtLastLine, GETENDATLASTLINE, bool); DeclareSciCallV1(SetEndAtLastLine, SETENDATLASTLINE, bool, flag); DeclareSciCallR0(GetXOffset, GETXOFFSET, int); DeclareSciCallV1(SetXOffset, SETXOFFSET, int, offset); DeclareSciCallV2(SetVisiblePolicy, SETVISIBLEPOLICY, int, flags, DocLn, lines); DeclareSciCallV0(MoveCaretInsideView, MOVECARETINSIDEVIEW); +DeclareSciCallV0(VerticalCentreCaret, VERTICALCENTRECARET); DeclareSciCallV2(ShowLines, SHOWLINES, DocLn, lnStart, DocLn, lnEnd); +DeclareSciCallV2(HideLines, HIDELINES, DocLn, lineStart, DocLn, lineEnd); +DeclareSciCallR0(GetAllLinesVisible, GETALLLINESVISIBLE, bool); DeclareSciCallR0(LinesOnScreen, LINESONSCREEN, DocLn); DeclareSciCallR1(GetLineVisible, GETLINEVISIBLE, bool, DocLn, line); DeclareSciCallR0(GetFirstVisibleLine, GETFIRSTVISIBLELINE, DocLn); @@ -527,7 +752,9 @@ DeclareSciCallV2(ScrollVertical, SCROLLVERTICAL, DocLn, docLine, DocLn, subLine) DeclareSciCallR1(VisibleFromDocLine, VISIBLEFROMDOCLINE, DocLn, DocLn, line); DeclareSciCallR1(DocLineFromVisible, DOCLINEFROMVISIBLE, DocLn, DocLn, line); +DeclareSciCallR0(GetHScrollBar, GETHSCROLLBAR, bool); DeclareSciCallV1(SetHScrollbar, SETHSCROLLBAR, bool, visible); +DeclareSciCallR0(GetVScrollBar, GETVSCROLLBAR, bool); DeclareSciCallV1(SetVScrollbar, SETVSCROLLBAR, bool, visible); @@ -541,9 +768,17 @@ DeclareSciCallV1(SetFoldFlags, SETFOLDFLAGS, int, flags); DeclareSciCallV1(FoldDisplayTextSetStyle, FOLDDISPLAYTEXTSETSTYLE, int, flags); DeclareSciCallR1(GetFoldParent, GETFOLDPARENT, DocLn, DocLn, line); DeclareSciCallR2(GetLastChild, GETLASTCHILD, DocLn, DocLn, line, int, level); +DeclareSciCallV2(SetFoldExpanded, SETFOLDEXPANDED, DocLn, line, bool, expanded); DeclareSciCallR1(GetFoldExpanded, GETFOLDEXPANDED, bool, DocLn, line); DeclareSciCallV1(ToggleFold, TOGGLEFOLD, DocLn, line); +DeclareSciCallV2(ToggleFoldShowText, TOGGLEFOLDSHOWTEXT, DocLn, line, const char*, text); +DeclareSciCallV2(FoldLine, FOLDLINE, DocLn, line, int, action); +DeclareSciCallV2(FoldChildren, FOLDCHILDREN, DocLn, line, int, action); +DeclareSciCallV2(ExpandChildren, EXPANDCHILDREN, DocLn, line, int, level); DeclareSciCallV1(FoldAll, FOLDALL, int, flags); +DeclareSciCallR0(FoldDisplayTextGetStyle, FOLDDISPLAYTEXTGETSTYLE, int); +DeclareSciCallR1(ContractedFoldNext, CONTRACTEDFOLDNEXT, DocLn, DocLn, lineStart); +DeclareSciCallR01(GetDefaultFoldDisplayText, GETDEFAULTFOLDDISPLAYTEXT, int, char*, text); DeclareSciCallV1(EnsureVisible, ENSUREVISIBLE, DocLn, line); DeclareSciCallV1(EnsureVisibleEnforcePolicy, ENSUREVISIBLEENFORCEPOLICY, DocLn, line); @@ -581,12 +816,45 @@ DeclareSciCallV2(SetStyling, SETSTYLING, DocPos, length, int, style); DeclareSciCallV1(StartStyling, STARTSTYLING, DocPos, position); DeclareSciCallR0(GetEndStyled, GETENDSTYLED, DocPos); +DeclareSciCallR1(StyleGetBold, STYLEGETBOLD, bool, int, style); +DeclareSciCallR1(StyleGetItalic, STYLEGETITALIC, bool, int, style); +DeclareSciCallR1(StyleGetSize, STYLEGETSIZE, int, int, style); +DeclareSciCallV2(StyleSetSize, STYLESETSIZE, int, style, int, sizePoints); +DeclareSciCallV2(StyleSetSizeFractional, STYLESETSIZEFRACTIONAL, int, style, int, sizeHundredthPoints); +DeclareSciCallR1(StyleGetSizeFractional, STYLEGETSIZEFRACTIONAL, int, int, style); +DeclareSciCallR1(StyleGetWeight, STYLEGETWEIGHT, int, int, style); +DeclareSciCallV2(StyleSetEOLFilled, STYLESETEOLFILLED, int, style, bool, eolFilled); +DeclareSciCallR1(StyleGetEOLFilled, STYLEGETEOLFILLED, bool, int, style); +DeclareSciCallV2(StyleSetUnderline, STYLESETUNDERLINE, int, style, bool, underline); +DeclareSciCallR1(StyleGetUnderline, STYLEGETUNDERLINE, bool, int, style); +DeclareSciCallV2(StyleSetCase, STYLESETCASE, int, style, int, caseVisible); +DeclareSciCallR1(StyleGetCase, STYLEGETCASE, int, int, style); +DeclareSciCallR1(StyleGetCharacterSet, STYLEGETCHARACTERSET, int, int, style); +DeclareSciCallR1(StyleGetVisible, STYLEGETVISIBLE, bool, int, style); +DeclareSciCallR1(StyleGetChangeable, STYLEGETCHANGEABLE, bool, int, style); DeclareSciCallR1(StyleGetHotspot, STYLEGETHOTSPOT, bool, int, style); DeclareSciCallV2(StyleSetHotspot, STYLESETHOTSPOT, int, style, bool, hotspot); -DeclareSciCallV1(SetHotspotActiveUnderline, SETHOTSPOTACTIVEUNDERLINE, bool, underline); -DeclareSciCallV1(SetHotspotSigleLine, SETHOTSPOTSINGLELINE, bool, singleline); +DeclareSciCallV2(StyleSetCheckMonospaced, STYLESETCHECKMONOSPACED, int, style, bool, checkMonospaced); +DeclareSciCallR1(StyleGetCheckMonospaced, STYLEGETCHECKMONOSPACED, bool, int, style); +DeclareSciCallV2(StyleSetStretch, STYLESETSTRETCH, int, style, int, stretch); +DeclareSciCallR1(StyleGetStretch, STYLEGETSTRETCH, int, int, style); +DeclareSciCallV2(StyleSetInvisibleRepresentation, STYLESETINVISIBLEREPRESENTATION, int, style, const char*, representation); +DeclareSciCallR2(StyleGetInvisibleRepresentation, STYLEGETINVISIBLEREPRESENTATION, int, int, style, char*, representation); +DeclareSciCallV2(StyleSetStrike, STYLESETSTRIKE, int, style, bool, strike); +DeclareSciCallR1(StyleGetStrike, STYLEGETSTRIKE, bool, int, style); +DeclareSciCallV2(SetHotspotActiveFore, SETHOTSPOTACTIVEFORE, bool, useSetting, COLORREF, fore); +DeclareSciCallR0(GetHotspotActiveFore, GETHOTSPOTACTIVEFORE, COLORREF); +DeclareSciCallV2(SetHotspotActiveBack, SETHOTSPOTACTIVEBACK, bool, useSetting, COLORREF, back); +DeclareSciCallR0(GetHotspotActiveBack, GETHOTSPOTACTIVEBACK, COLORREF); +DeclareSciCallV1(SetHotspotActiveUnderline, SETHOTSPOTACTIVEUNDERLINE, bool, underline); +DeclareSciCallR0(GetHotspotActiveUnderline, GETHOTSPOTACTIVEUNDERLINE, bool); +DeclareSciCallV1(SetHotspotSingleLine, SETHOTSPOTSINGLELINE, bool, singleline); +DeclareSciCallR0(GetHotspotSingleLine, GETHOTSPOTSINGLELINE, bool); + +DeclareSciCallR0(GetViewWS, GETVIEWWS, int); DeclareSciCallV1(SetViewWS, SETVIEWWS, int, wspc); +DeclareSciCallR0(GetViewEOL, GETVIEWEOL, bool); DeclareSciCallV1(SetViewEOL, SETVIEWEOL, bool, eols); DeclareSciCallR2(StyleGetFont, STYLEGETFONT, int, int, style, char*, fontname); @@ -610,8 +878,11 @@ DeclareSciCallV1(SetWrapMode, SETWRAPMODE, int, mode); DeclareSciCallR0(GetWrapMode, GETWRAPMODE, int); DeclareSciCallV1(SetWrapIndentMode, SETWRAPINDENTMODE, int, mode); DeclareSciCallR0(GetWrapIndentMode, GETWRAPINDENTMODE, int); +DeclareSciCallR0(GetWrapStartIndent, GETWRAPSTARTINDENT, int); DeclareSciCallV1(SetWrapStartIndent, SETWRAPSTARTINDENT, int, mode); +DeclareSciCallR0(GetWrapVisualFlags, GETWRAPVISUALFLAGS, int); DeclareSciCallV1(SetWrapVisualFlags, SETWRAPVISUALFLAGS, int, opts); +DeclareSciCallR0(GetWrapVisualFlagsLocation, GETWRAPVISUALFLAGSLOCATION, int); DeclareSciCallV1(SetWrapVisualFlagsLocation, SETWRAPVISUALFLAGSLOCATION, int, opts); DeclareSciCallR1(WrapCount, WRAPCOUNT, DocLn, DocLn, line); DeclareSciCallR0(GetIndentationGuides, GETINDENTATIONGUIDES, int); @@ -644,6 +915,11 @@ DeclareSciCallR1(GetLineIndentPosition, GETLINEINDENTPOSITION, DocPos, DocLn, li DeclareSciCallV1(SetIndentationGuides, SETINDENTATIONGUIDES, int, iview); DeclareSciCallV1(SetHighLightGuide, SETHIGHLIGHTGUIDE, int, column); +DeclareSciCallR0(GetHighlightGuide, GETHIGHLIGHTGUIDE, DocPos); +// Tab Stops +DeclareSciCallV1(ClearTabStops, CLEARTABSTOPS, DocLn, line); +DeclareSciCallV2(AddTabStop, ADDTABSTOP, DocLn, line, int, x); +DeclareSciCallR2(GetNextTabStop, GETNEXTTABSTOP, int, DocLn, line, int, x); DeclareSciCallR1(BraceMatch, BRACEMATCH, DocPos, DocPos, pos); DeclareSciCallR2(BraceMatchNext, BRACEMATCHNEXT, DocPos, DocPos, pos, DocPos, posStart); @@ -657,18 +933,26 @@ DeclareSciCallV2(BraceBadLightIndicator, BRACEBADLIGHTINDICATOR, bool, use, int, // // Margins // +DeclareSciCallR0(GetMarginOptions, GETMARGINOPTIONS, int); DeclareSciCallV1(SetMarginOptions, SETMARGINOPTIONS, int, options); +DeclareSciCallR1(GetMarginTypeN, GETMARGINTYPEN, int, int, margin); DeclareSciCallV2(SetMarginTypeN, SETMARGINTYPEN, uintptr_t, margin, int, type); DeclareSciCallR1(GetMarginWidthN, GETMARGINWIDTHN, int, uintptr_t, margin); DeclareSciCallV2(SetMarginWidthN, SETMARGINWIDTHN, uintptr_t, margin, int, pixelWidth); +DeclareSciCallR1(GetMarginMaskN, GETMARGINMASKN, int, int, margin); DeclareSciCallV2(SetMarginMaskN, SETMARGINMASKN, uintptr_t, margin, int, mask); +DeclareSciCallR1(GetMarginSensitiveN, GETMARGINSENSITIVEN, bool, int, margin); DeclareSciCallV2(SetMarginSensitiveN, SETMARGINSENSITIVEN, uintptr_t, margin, bool, sensitive); -DeclareSciCallV2(SetMarginBackN, SETMARGINBACKN, uintptr_t, margin, COLORREF, colour); +DeclareSciCallR1(GetMarginCursorN, GETMARGINCURSORN, int, int, margin); DeclareSciCallV2(SetMarginCursorN, SETMARGINCURSORN, uintptr_t, margin, int, cursor); +DeclareSciCallR1(GetMarginBackN, GETMARGINBACKN, COLORREF, int, margin); +DeclareSciCallV2(SetMarginBackN, SETMARGINBACKN, uintptr_t, margin, COLORREF, colour); DeclareSciCallV2(SetFoldMarginColour, SETFOLDMARGINCOLOUR, bool, useSetting, COLORREF, colour); DeclareSciCallV2(SetFoldMarginHiColour, SETFOLDMARGINHICOLOUR, bool, useSetting, COLORREF, colour); DeclareSciCallV01(SetDefaultFoldDisplayText, SETDEFAULTFOLDDISPLAYTEXT, const char*, text); +DeclareSciCallR0(GetMarginLeft, GETMARGINLEFT, int); DeclareSciCallV01(SetMarginLeft, SETMARGINLEFT, int, width); +DeclareSciCallR0(GetMarginRight, GETMARGINRIGHT, int); DeclareSciCallV01(SetMarginRight, SETMARGINRIGHT, int, width); DeclareSciCallR2(TextWidth, TEXTWIDTH, int, int, styleNumber, const char *, text); @@ -687,8 +971,14 @@ DeclareSciCallV2(MarkerSetBackSelected, MARKERSETBACKSELECTED, int, markerID, CO DeclareSciCallV2(MarkerSetBackSelectedTranslucent, MARKERSETBACKSELECTEDTRANSLUCENT, int, markerID, COLORALPHAREF, colouralpha); DeclareSciCallV2(MarkerSetStrokeWidth, MARKERSETSTROKEWIDTH, int, markerID, int, hundredths); DeclareSciCallV1(MarkerEnableHighlight, MARKERENABLEHIGHLIGHT, bool, flag); +DeclareSciCallR1(MarkerGetLayer, MARKERGETLAYER, int, int, markerNumber); DeclareSciCallV2(MarkerSetLayer, MARKERSETLAYER, int, markerID, int, layer); DeclareSciCallV2(MarkerSetAlpha, MARKERSETALPHA, int, markerID, int, alpha); +DeclareSciCallR1(MarkerSymbolDefined, MARKERSYMBOLDEFINED, int, int, markerNumber); +DeclareSciCallR1(MarkerLineFromHandle, MARKERLINEFROMHANDLE, DocLn, int, markerHandle); +DeclareSciCallV1(MarkerDeleteHandle, MARKERDELETEHANDLE, int, markerHandle); +DeclareSciCallV2(MarkerDefinePixmap, MARKERDEFINEPIXMAP, int, markerNumber, const char*, pixmap); +DeclareSciCallV2(MarkerDefineRGBAImage, MARKERDEFINERGBAIMAGE, int, markerNumber, const char*, pixels); DeclareSciCallR2(MarkerAdd, MARKERADD, int, DocLn, line, int, markerID); DeclareSciCallV2(MarkerAddSet, MARKERADDSET, DocLn, line, int, markerMask); DeclareSciCallV2(MarkerDelete, MARKERDELETE, DocLn, line, int, markerID); @@ -711,15 +1001,29 @@ DeclareSciCallR1(IndicGetStrokeWidth, INDICGETSTROKEWIDTH, int, int, indicID); DeclareSciCallV2(IndicSetUnder, INDICSETUNDER, int, indicID, bool, under); DeclareSciCallR1(IndicGetUnder, INDICGETUNDER, bool, int, indicID); DeclareSciCallV2(IndicSetHoverStyle, INDICSETHOVERSTYLE, int, indicID, int, style); +DeclareSciCallR1(IndicGetHoverStyle, INDICGETHOVERSTYLE, int, int, indicator); DeclareSciCallV2(IndicSetHoverFore, INDICSETHOVERFORE, int, indicID, COLORREF, colour); +DeclareSciCallR1(IndicGetHoverFore, INDICGETHOVERFORE, COLORREF, int, indicator); DeclareSciCallV2(IndicSetAlpha, INDICSETALPHA, int, indicID, int, alpha); +DeclareSciCallR1(IndicGetAlpha, INDICGETALPHA, int, int, indicator); DeclareSciCallV2(IndicSetOutlineAlpha, INDICSETOUTLINEALPHA, int, indicID, int, alpha); +DeclareSciCallR1(IndicGetOutlineAlpha, INDICGETOUTLINEALPHA, int, int, indicator); +DeclareSciCallV2(IndicSetFlags, INDICSETFLAGS, int, indicator, int, flags); +DeclareSciCallR1(IndicGetFlags, INDICGETFLAGS, int, int, indicator); DeclareSciCallV1(SetIndicatorCurrent, SETINDICATORCURRENT, int, indicID); +DeclareSciCallR0(GetIndicatorCurrent, GETINDICATORCURRENT, int); +DeclareSciCallV1(SetIndicatorValue, SETINDICATORVALUE, int, value); +DeclareSciCallR0(GetIndicatorValue, GETINDICATORVALUE, int); DeclareSciCallV2(IndicatorFillRange, INDICATORFILLRANGE, DocPos, position, DocPos, length); DeclareSciCallV2(IndicatorClearRange, INDICATORCLEARRANGE, DocPos, position, DocPos, length); +DeclareSciCallR1(IndicatorAllOnFor, INDICATORALLONFOR, int, DocPos, pos); DeclareSciCallR2(IndicatorValueAt, INDICATORVALUEAT, int, int, indicID, DocPos, position); DeclareSciCallR2(IndicatorStart, INDICATORSTART, int, int, indicID, DocPos, position); DeclareSciCallR2(IndicatorEnd, INDICATOREND, int, int, indicID, DocPos, position); +// macOS Find Indicator +DeclareSciCallV2(FindIndicatorShow, FINDINDICATORSHOW, DocPos, start, DocPos, end); +DeclareSciCallV2(FindIndicatorFlash, FINDINDICATORFLASH, DocPos, start, DocPos, end); +DeclareSciCallV0(FindIndicatorHide, FINDINDICATORHIDE); //============================================================================= @@ -727,8 +1031,18 @@ DeclareSciCallR2(IndicatorEnd, INDICATOREND, int, int, indicID, DocPos, position // Lexer // DeclareSciCallV2(SetProperty, SETPROPERTY, const char*, key, const char*, value); +DeclareSciCallR2(GetProperty, GETPROPERTY, int, const char*, key, char*, value); +DeclareSciCallR2(GetPropertyExpanded, GETPROPERTYEXPANDED, int, const char*, key, char*, value); +DeclareSciCallR2(GetPropertyInt, GETPROPERTYINT, int, const char*, key, int, defaultValue); DeclareSciCallV2(SetKeywords, SETKEYWORDS, int, keywordset, const char*, keywords); DeclareSciCallV2(Colourise, COLOURISE, DocPos, startPos, DocPos, endPos); +DeclareSciCallR01(GetLexerLanguage, GETLEXERLANGUAGE, int, char*, language); +DeclareSciCallR2(PrivateLexerCall, PRIVATELEXERCALL, sptr_t, int, operation, sptr_t, pointer); +DeclareSciCallR01(PropertyNames, PROPERTYNAMES, int, char*, names); +DeclareSciCallR1(PropertyType, PROPERTYTYPE, int, const char*, name); +DeclareSciCallR2(DescribeProperty, DESCRIBEPROPERTY, int, const char*, name, char*, description); +DeclareSciCallR01(DescribeKeyWordSets, DESCRIBEKEYWORDSETS, int, char*, descriptions); +DeclareSciCallR0(GetLineEndTypesSupported, GETLINEENDTYPESSUPPORTED, int); //============================================================================= @@ -737,8 +1051,11 @@ DeclareSciCallV2(Colourise, COLOURISE, DocPos, startPos, DocPos, endPos); // DeclareSciCallV1(SetCursor, SETCURSOR, int, flags); +DeclareSciCallR0(GetCaretStyle, GETCARETSTYLE, int); DeclareSciCallV1(SetCaretStyle, SETCARETSTYLE, int, style); +DeclareSciCallR0(GetCaretWidth, GETCARETWIDTH, int); DeclareSciCallV1(SetCaretWidth, SETCARETWIDTH, int, pixel); +DeclareSciCallR0(GetCaretPeriod, GETCARETPERIOD, int); DeclareSciCallV1(SetCaretPeriod, SETCARETPERIOD, int, msec); DeclareSciCallV1(SetAdditionalCaretsBlink, SETADDITIONALCARETSBLINK, bool, flag); DeclareSciCallV1(SetAdditionalCaretsVisible, SETADDITIONALCARETSVISIBLE, bool, flag); @@ -754,6 +1071,20 @@ DeclareSciCallV0(EndUndoAction, ENDUNDOACTION); DeclareSciCallR0(GetUndoCollection, GETUNDOCOLLECTION, bool); DeclareSciCallV1(SetUndoCollection, SETUNDOCOLLECTION, bool, bCollectUndo); DeclareSciCallR0(GetUndoSequence, GETUNDOSEQUENCE, int); +DeclareSciCallR0(GetUndoActions, GETUNDOACTIONS, int); +DeclareSciCallV1(SetUndoSavePoint, SETUNDOSAVEPOINT, int, action); +DeclareSciCallR0(GetUndoSavePoint, GETUNDOSAVEPOINT, int); +DeclareSciCallV1(SetUndoDetach, SETUNDODETACH, int, action); +DeclareSciCallR0(GetUndoDetach, GETUNDODETACH, int); +DeclareSciCallV1(SetUndoTentative, SETUNDOTENTATIVE, int, action); +DeclareSciCallR0(GetUndoTentative, GETUNDOTENTATIVE, int); +DeclareSciCallV1(SetUndoCurrent, SETUNDOCURRENT, int, action); +DeclareSciCallR0(GetUndoCurrent, GETUNDOCURRENT, int); +DeclareSciCallV2(PushUndoActionType, PUSHUNDOACTIONTYPE, int, type, DocPos, pos); +DeclareSciCallV2(ChangeLastUndoActionText, CHANGELASTUNDOACTIONTEXT, DocPos, length, const char*, text); +DeclareSciCallR1(GetUndoActionType, GETUNDOACTIONTYPE, int, int, action); +DeclareSciCallR1(GetUndoActionPosition, GETUNDOACTIONPOSITION, DocPos, int, action); +DeclareSciCallR2(GetUndoActionText, GETUNDOACTIONTEXT, int, int, action, char*, text); DeclareSciCallV1(SetUndoSelectionHistory, SETUNDOSELECTIONHISTORY, int, option); DeclareSciCallR0(GetUndoSelectionHistory, GETUNDOSELECTIONHISTORY, int); @@ -762,11 +1093,111 @@ DeclareSciCallR0(GetUndoSelectionHistory, GETUNDOSELECTIONHISTORY, int); // // IME // +DeclareSciCallR0(GetIMEInteraction, GETIMEINTERACTION, int); DeclareSciCallV1(SetIMEInteraction, SETIMEINTERACTION, int, interact); DeclareSciCallR0(IsIMEOpen, ISIMEOPEN, bool); DeclareSciCallR0(IsIMEModeCJK, ISIMEMODECJK, bool); +//============================================================================= +// +// Annotations +// +DeclareSciCallV2(AnnotationSetText, ANNOTATIONSETTEXT, DocLn, line, const char*, text); +DeclareSciCallR2(AnnotationGetText, ANNOTATIONGETTEXT, int, DocLn, line, char*, text); +DeclareSciCallV2(AnnotationSetStyle, ANNOTATIONSETSTYLE, DocLn, line, int, style); +DeclareSciCallR1(AnnotationGetStyle, ANNOTATIONGETSTYLE, int, DocLn, line); +DeclareSciCallV2(AnnotationSetStyles, ANNOTATIONSETSTYLES, DocLn, line, const char*, styles); +DeclareSciCallR2(AnnotationGetStyles, ANNOTATIONGETSTYLES, int, DocLn, line, char*, styles); +DeclareSciCallR1(AnnotationGetLines, ANNOTATIONGETLINES, int, DocLn, line); +DeclareSciCallV0(AnnotationClearAll, ANNOTATIONCLEARALL); +DeclareSciCallV1(AnnotationSetVisible, ANNOTATIONSETVISIBLE, int, visible); +DeclareSciCallR0(AnnotationGetVisible, ANNOTATIONGETVISIBLE, int); +DeclareSciCallV1(AnnotationSetStyleOffset, ANNOTATIONSETSTYLEOFFSET, int, style); +DeclareSciCallR0(AnnotationGetStyleOffset, ANNOTATIONGETSTYLEOFFSET, int); + + +//============================================================================= +// +// EOL Annotations +// +DeclareSciCallV2(EOLAnnotationSetText, EOLANNOTATIONSETTEXT, DocLn, line, const char*, text); +DeclareSciCallR2(EOLAnnotationGetText, EOLANNOTATIONGETTEXT, int, DocLn, line, char*, text); +DeclareSciCallV2(EOLAnnotationSetStyle, EOLANNOTATIONSETSTYLE, DocLn, line, int, style); +DeclareSciCallR1(EOLAnnotationGetStyle, EOLANNOTATIONGETSTYLE, int, DocLn, line); +DeclareSciCallV0(EOLAnnotationClearAll, EOLANNOTATIONCLEARALL); +DeclareSciCallV1(EOLAnnotationSetVisible, EOLANNOTATIONSETVISIBLE, int, visible); +DeclareSciCallR0(EOLAnnotationGetVisible, EOLANNOTATIONGETVISIBLE, int); +DeclareSciCallV1(EOLAnnotationSetStyleOffset, EOLANNOTATIONSETSTYLEOFFSET, int, style); +DeclareSciCallR0(EOLAnnotationGetStyleOffset, EOLANNOTATIONGETSTYLEOFFSET, int); + + +//============================================================================= +// +// Margin Text +// +DeclareSciCallV2(MarginSetText, MARGINSETTEXT, DocLn, line, const char*, text); +DeclareSciCallR2(MarginGetText, MARGINGETTEXT, int, DocLn, line, char*, text); +DeclareSciCallV2(MarginSetStyle, MARGINSETSTYLE, DocLn, line, int, style); +DeclareSciCallR1(MarginGetStyle, MARGINGETSTYLE, int, DocLn, line); +DeclareSciCallV2(MarginSetStyles, MARGINSETSTYLES, DocLn, line, const char*, styles); +DeclareSciCallR2(MarginGetStyles, MARGINGETSTYLES, int, DocLn, line, char*, styles); +DeclareSciCallV0(MarginTextClearAll, MARGINTEXTCLEARALL); +DeclareSciCallV1(MarginSetStyleOffset, MARGINSETSTYLEOFFSET, int, style); +DeclareSciCallR0(MarginGetStyleOffset, MARGINGETSTYLEOFFSET, int); + + +//============================================================================= +// +// Substyles +// +DeclareSciCallR2(AllocateSubStyles, ALLOCATESUBSTYLES, int, int, styleBase, int, numberStyles); +DeclareSciCallR1(GetSubStylesStart, GETSUBSTYLESSTART, int, int, styleBase); +DeclareSciCallR1(GetSubStylesLength, GETSUBSTYLESLENGTH, int, int, styleBase); +DeclareSciCallV0(FreeSubStyles, FREESUBSTYLES); +DeclareSciCallV2(SetIdentifiers, SETIDENTIFIERS, int, style, const char*, identifiers); +DeclareSciCallR0(DistanceToSecondaryStyles, DISTANCETOSECONDARYSTYLES, int); +DeclareSciCallR01(GetSubStyleBases, GETSUBSTYLEBASES, int, char*, styles); +DeclareSciCallR1(GetStyleFromSubStyle, GETSTYLEFROMSUBSTYLE, int, int, subStyle); +DeclareSciCallR1(GetPrimaryStyleFromStyle, GETPRIMARYSTYLEFROMSTYLE, int, int, style); +DeclareSciCallR0(GetNamedStyles, GETNAMEDSTYLES, int); +DeclareSciCallR2(NameOfStyle, NAMEOFSTYLE, int, int, style, char*, name); +DeclareSciCallR2(TagsOfStyle, TAGSOFSTYLE, int, int, style, char*, tags); +DeclareSciCallR2(DescriptionOfStyle, DESCRIPTIONOFSTYLE, int, int, style, char*, description); +DeclareSciCallV0(ReleaseAllExtendedStyles, RELEASEALLEXTENDEDSTYLES); +DeclareSciCallR1(AllocateExtendedStyles, ALLOCATEEXTENDEDSTYLES, int, int, numberStyles); + + +//============================================================================= +// +// Printing +// +DeclareSciCallV1(SetPrintMagnification, SETPRINTMAGNIFICATION, int, magnification); +DeclareSciCallR0(GetPrintMagnification, GETPRINTMAGNIFICATION, int); +DeclareSciCallV1(SetPrintColourMode, SETPRINTCOLOURMODE, int, mode); +DeclareSciCallR0(GetPrintColourMode, GETPRINTCOLOURMODE, int); +DeclareSciCallV1(SetPrintWrapMode, SETPRINTWRAPMODE, int, wrapMode); +DeclareSciCallR0(GetPrintWrapMode, GETPRINTWRAPMODE, int); +DeclareSciCallR2(FormatRange, FORMATRANGE, DocPos, bool, draw, struct Sci_RangeToFormat*, fr); +DeclareSciCallR2(FormatRangeFull, FORMATRANGEFULL, DocPos, bool, draw, struct Sci_RangeToFormatFull*, fr); + + +//============================================================================= +// +// Recording +// +DeclareSciCallV0(StartRecord, STARTRECORD); +DeclareSciCallV0(StopRecord, STOPRECORD); + + +//============================================================================= +// +// Drag and Drop +// +DeclareSciCallR0(GetDragDropEnabled, GETDRAGDROPENABLED, bool); +DeclareSciCallV1(SetDragDropEnabled, SETDRAGDROPENABLED, bool, dragDropEnabled); + + //============================================================================= // // Utilities diff --git a/src/Styles.c b/src/Styles.c index 405546318..d6e34f537 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -1951,7 +1951,7 @@ void Style_SetUrlHotSpot(HWND hwnd) // style for hotspot //~SciCall_StyleSetHotspot(_STYLE_GETSTYLEID(STY_URL_HOTSPOT), true); //~SciCall_SetHotspotActiveUnderline(false); - //~SciCall_SetHotspotSigleLine(true); + //~SciCall_SetHotspotSingleLine(true); } diff --git a/src/timsort/AUTHORS b/src/timsort/AUTHORS new file mode 100644 index 000000000..263860b6a --- /dev/null +++ b/src/timsort/AUTHORS @@ -0,0 +1,11 @@ +Maintainer: Patrick Perry + - initial port from Java + + +Other authors: + +Ashok P. Nadkarni + - fixes for Windows + - reentrant version + - bugfix on Linux (issue #2) + diff --git a/src/timsort/LICENSE b/src/timsort/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/src/timsort/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/timsort/README.md b/src/timsort/README.md new file mode 100644 index 000000000..84ab627c7 --- /dev/null +++ b/src/timsort/README.md @@ -0,0 +1,156 @@ +This is a fairly straightforward C99 port of the Java/Android +implementation of [Timsort](http://en.wikipedia.org/wiki/Timsort), which +itself is a port of Tim Peters's list sort for Python. Most of the +comments are from the earlier two implementations, except those annotated +by the initials POP. + +The prototype for the sorting function is + + int timsort(void *base, size_t nel, size_t width, + int (*compar) (const void *, const void *)); + +This resembles the standard library `qsort` function. The function +returns `0` on success and `-1` on failure. Failure only happens when +the routine can't allocate the necessary temporary array or if the +comparator is invalid. + +The source code for the (Apache 2.0 Licensed) Java version is included in +[the JSR-166 proposal](http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/TimSort.java?view=co). + +This version would not be possiple without all the hard work on the Java +version. Kudos to google for open-sourcing their code. This implementation +has same license, and maintains the "Android Open Source Project" +copyright on the code. An even bigger "thank you" goes to Tim Peters, +for devising and documenting the algorithm in the first place. + + +Differences from the Java version +================================= + +C doesn't have exceptions, so we use `errno` and return codes instead. Another +difference is that C has pointers, so there is no need to pass around a `lo` +parameter to specify a range of values in an array. +One major change is that we use 'size_t' instead of 'int' as the index type; this +required some extra care in checking for overflow and ensuring that +the values are always non-negative. Moreover, some modifications needed to +be made to allow for differences on 64-bit architectures. These changes +are explained in more detail below. + + +Use return codes instead of exceptions +-------------------------------------- + +In the C implementation, if `malloc` or `realloc` fails to allocate the +necessary temporary array, the sorting routine returns `-1`. +Likewise, if `mergeLo` or `mergeHi` discovers that the comparison +method violates its contract, then it sets `errno` to `EINVAL` and +the sorting routine returns `-1`. + + +Use pointers instead of arrays with offsets +------------------------------------------- + +C has pointers, so there is no need to pass around "lo" parameters. Instead, +we store the pointer to the base of the array range. + + +Switch from `int` to `size_t` +----------------------------- + +The code takes special care to ensure that integer values never become +negative; in particular: + +- In the Java version of `gallopLeft`, the `lastOfs` variable is + allowed to become `-1`. To prevent this, in the `else` branch + we replace + + lastOfs = hint - ofs; + + with + + lastOfs = hint + 1 - ofs; + + for symmetry, in the `if` branch we replace `lastOfs += hint` with + `lastOfs += hint + 1`. Finally, we replace + + assert(-1 <= lastOfs && lastOfs < ofs && ofs <= len); + + with + + assert(0 <= lastOfs && lastOfs <= ofs && ofs <= len); + + and remove the statement `lastOfs++;` which happens after + the conditional. Similar changes appear in `gallopRight`. + +- In `mergeLo`, we replace + + minGallop--; + + with + + if (minGallop > 0) + minGallop--; + + Then, we remove following lines, which appear after the loop: + + if (minGallop < 0) + minGallop = 0; + + Similar changes appear in `mergeHi`. + +The rest of the changes allow for `size_t` to be up to 64-bits long: + +- In the TimSort constructor (`timsort_init`), the line + + stackLen = (len < 120 ? 5 : len < 1542 ? 10 : len < 119151 ? 19 : 40); + + gets replaced with with + + stackLen = (len < 359 ? 5 + : len < 4220 ? 10 + : len < 76210 ? 16 : len < 4885703256 ? 39 : 85); + + Note that the bounds on `len` are slightly different. The + justification for these values is given in a comment above the assignment. + +- In `ensureCapacity`, we add an additional operation: + + if (sizeof(newSize) > 4) + newSize |= newSize >> 32; + + +Related projects +================ + +Christopher Swenson has a macro-based C implementation of timsort at +[https://github.com/swenson/sort/](https://github.com/swenson/sort/). + + +Performance +=========== + +In a crude benchmark, sorting small, medium, and large arrays of +uniformly chosen 64-bit integers, performance was comparable to the +stdlib `qsort` implementation; Swenson's macro-based timsort +implementation was about 1.4 times faster than both. Swenson's +implementation has the edge here because it avoids the overhead +of a function call when comparing two elements. + + +Reentrant version +================= + +A reentrant variation of the `timsort` function - `timsort_r` - has been +defined which can pass an additional argument to the comparison function +purely for the calling application's own use. This is similar to the GNU +and C11 variations of the standard `qsort` function (*not* Windows +`qsort_s` or BSD `qsort_r`). + +The prototype for this sorting function is + + int timsort_r(void *base, size_t nel, size_t width, + int (*compar) (const void *, const void *, void *), + void *context); + +The additional context parameter is passed to the comparison callback +as the last argument. diff --git a/src/timsort/stresstest.c b/src/timsort/stresstest.c new file mode 100644 index 000000000..e310dc951 --- /dev/null +++ b/src/timsort/stresstest.c @@ -0,0 +1,166 @@ +/* Modified version of Christopher Swenson's 'stresstest.c' from + * https://github.com/swenson/sort/blob/master/stresstest.c + * + * Copyright (c) 2011 Patrick 0. Perry + * Copyright (c) 2010 Christopher Swenson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include "timsort.h" + +#ifdef _WIN32 +#define lrand48 rand +#endif + +/* Used to control the stress test */ +#define SEED 123 +#define MAXSIZE 1000 +#define TESTS 100000 +#define TYPE int + +/* helper functions */ +void verify(TYPE *dst, const size_t size) +{ + size_t i; + for (i = 1; i < size; i++) + { + if (dst[i - 1] > dst[i]) + { + printf("Verify failed! at %zd\n", i); + //for (i = i - 2; i < size; i++) + // printf(" %lld", dst[i]); + //printf("\n"); + break; + } + } +} + +static void fill(TYPE *dst, const size_t size) +{ + size_t i; + for (i = 0; i < size; i++) + { + dst[i] = lrand48(); + } +} + +static int compare(const void *a, const void *b) +{ + const TYPE da = *((const TYPE *) a); + const TYPE db = *((const TYPE *) b); + return (da < db) ? -1 : (da == db) ? 0 : 1; +} + +static int compare_arg(const void *a, const void *b, void *arg) +{ + const TYPE da = *((const TYPE *) a); + const TYPE db = *((const TYPE *) b); + return (da < db) ? -1 : (da == db) ? 0 : 1; +} + + +void run_tests(void) +{ + int err; + int test; + TYPE *dst; + size_t size; + + printf("Running tests\n"); +#ifndef _WIN32 + srand48(SEED); +#endif + +#if 1 + printf("timsort\n"); + for (test = 0; test < TESTS; test++) + { + size = (lrand48() % (MAXSIZE + 1)); + dst = malloc(size * sizeof(dst[0])); + if (!dst && size) { + perror("malloc failed"); + exit(EXIT_FAILURE); + } + + fill(dst, size); +#ifdef USE_CMP_ARG + err = timsort_r(dst, size, sizeof(dst[0]), compare_arg, NULL); +#else + err = timsort(dst, size, sizeof(dst[0]), compare); +#endif + if (err) { + perror("timsort failed"); + exit(EXIT_FAILURE); + } + verify(dst, size); +#ifdef USE_CMP_ARG + err = timsort_r(dst, size, sizeof(dst[0]), compare_arg, NULL); +#else + err = timsort(dst, size, sizeof(dst[0]), compare); +#endif + if (err) { + perror("timsort failed"); + exit(EXIT_FAILURE); + } + verify(dst, size); + + free(dst); + } +#else + printf("mergesort\n"); + for (test = 0; test < TESTS; test++) + { + size = (lrand48() % (MAXSIZE + 1)); + dst = malloc(size * sizeof(dst[0])); + if (!dst && size) { + perror("malloc failed"); + exit(EXIT_FAILURE); + } + + fill(dst, size); + err = mergesort(dst, size, sizeof(dst[0]), compare); + if (err) { + perror("mergesort failed"); + exit(EXIT_FAILURE); + } + verify(dst, size); + err = mergesort(dst, size, sizeof(dst[0]), compare); + if (err) { + perror("mergesort failed"); + exit(EXIT_FAILURE); + } + verify(dst, size); + + free(dst); + } +#endif +} + +int main(void) +{ + run_tests(); + return EXIT_SUCCESS; +} diff --git a/src/timsort/timsort-impl.h b/src/timsort/timsort-impl.h new file mode 100644 index 000000000..eb81c183d --- /dev/null +++ b/src/timsort/timsort-impl.h @@ -0,0 +1,837 @@ +/* + * Copyright (C) 2011 Patrick O. Perry + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +static void NAME(binarySort) (void *a, size_t hi, size_t start, + CMPPARAMS(compare, carg), size_t width); +static size_t NAME(countRunAndMakeAscending) (void *a, size_t hi, + CMPPARAMS(compare, carg), + size_t width); +static void NAME(reverseRange) (void *a, size_t hi, size_t width); +static int NAME(mergeCollapse) (struct timsort * ts, size_t width); +static int NAME(mergeForceCollapse) (struct timsort * ts, size_t width); +static int NAME(mergeAt) (struct timsort * ts, size_t i, size_t width); +static size_t NAME(gallopLeft) (void *key, void *base, size_t len, + size_t hint, CMPPARAMS(compare, carg), + size_t width); +static size_t NAME(gallopRight) (void *key, void *base, size_t len, + size_t hint, CMPPARAMS(compare, carg), + size_t width); +static int NAME(mergeLo) (struct timsort * ts, void *base1, size_t len1, + void *base2, size_t len2, size_t width); +static int NAME(mergeHi) (struct timsort * ts, void *base1, size_t len1, + void *base2, size_t len2, size_t width); + +static int NAME(timsort) (void *a, size_t nel, size_t width, CMPPARAMS(c, carg)) +{ + int err = SUCCESS; + struct timsort ts; + size_t minRun; + + assert(a || !nel || !width); + assert(c); + + if (nel < 2 || !width) + return err; // Arrays of size 0 and 1 are always sorted + + // If array is small, do a "mini-TimSort" with no merges + if (nel < MIN_MERGE) { + size_t initRunLen = + CALL(countRunAndMakeAscending) (a, nel, CMPARGS(c, carg), width); + CALL(binarySort) (a, nel, initRunLen, CMPARGS(c, carg), width); + return err; + } + + /** + * March over the array once, left to right, finding natural runs, + * extending short natural runs to minRun elements, and merging runs + * to maintain stack invariant. + */ + if ((err = timsort_init(&ts, a, nel, CMPARGS(c, carg), width))) + return err; + + minRun = minRunLength(nel); + do { + // Identify next run + size_t runLen = + CALL(countRunAndMakeAscending) (a, nel, CMPARGS(c, carg), width); + + // If run is short, extend to min(minRun, nel) + if (runLen < minRun) { + size_t force = nel <= minRun ? nel : minRun; + CALL(binarySort) (a, force, runLen, CMPARGS(c, carg), width); + runLen = force; + } + // Push run onto pending-run stack, and maybe merge + pushRun(&ts, a, runLen); + if ((err = CALL(mergeCollapse) (&ts, width))) + goto out; + + // Advance to find next run + a = ELEM(a, runLen); + nel -= runLen; + } while (nel != 0); + + // Merge all remaining runs to complete sort + if ((err = CALL(mergeForceCollapse) (&ts, width))) + goto out; + + assert(ts.stackSize == 1); +out: + timsort_deinit(&ts); + return err; +} + +/** + * Sorts the specified portion of the specified array using a binary + * insertion sort. This is the best method for sorting small numbers + * of elements. It requires O(n log n) compares, but O(n^2) data + * movement (worst case). + * + * If the initial part of the specified range is already sorted, + * this method can take advantage of it: the method assumes that the + * elements from index {@code lo}, inclusive, to {@code start}, + * exclusive are already sorted. + * + * @param a the array in which a range is to be sorted + * @param hi the index after the last element in the range to be sorted + * @param start the index of the first element in the range that is + * not already known to be sorted ({@code lo <= start <= hi}) + * @param c comparator to used for the sort + */ +static void NAME(binarySort) (void *a, size_t hi, size_t start, + CMPPARAMS(compare, carg), size_t width) { + DEFINE_TEMP(pivot); + char *startp; + + assert(start <= hi); + + if (start == 0) + start++; + + startp = ELEM(a, start); + + for (; start < hi; start++, startp = INCPTR(startp)) { + + // Set left (and right) to the index where a[start] (pivot) belongs + char *leftp = a; + size_t right = start; + size_t n; + + /* + * Invariants: + * pivot >= all in [0, left). + * pivot < all in [right, start). + */ + while (0 < right) { + size_t mid = right >> 1; + void *midp = ELEM(leftp, mid); + if (CMP(compare, carg, startp, midp) < 0) { + right = mid; + } else { + leftp = INCPTR(midp); + right -= (mid + 1); + } + } + assert(0 == right); + + /* + * The invariants still hold: pivot >= all in [lo, left) and + * pivot < all in [left, start), so pivot belongs at left. Note + * that if there are elements equal to pivot, left points to the + * first slot after them -- that's why this sort is stable. + * Slide elements over to make room to make room for pivot. + */ + n = startp - leftp; // The number of bytes to move + + ASSIGN(pivot, startp); + memmove(INCPTR(leftp), leftp, n); // POP: overlaps + + // a[left] = pivot; + ASSIGN(leftp, pivot); + } + (void)width; +} + +/** + * Returns the length of the run beginning at the specified position in + * the specified array and reverses the run if it is descending (ensuring + * that the run will always be ascending when the method returns). + * + * A run is the longest ascending sequence with: + * + * a[0] <= a[1] <= a[2] <= ... + * + * or the longest descending sequence with: + * + * a[0] > a[1] > a[2] > ... + * + * For its intended use in a stable mergesort, the strictness of the + * definition of "descending" is needed so that the call can safely + * reverse a descending sequence without violating stability. + * + * @param a the array in which a run is to be counted and possibly reversed + * @param hi index after the last element that may be contained in the run. + * It is required that {@code 0 < hi}. + * @param compare the comparator to used for the sort + * @return the length of the run beginning at the specified position in + * the specified array + */ +static size_t NAME(countRunAndMakeAscending) (void *a, size_t hi, + CMPPARAMS(compare, carg), size_t width) +{ + size_t runHi = 1; + char *cur; + char *next; + + assert(0 < hi); + if (runHi == hi) + return 1; + + cur = INCPTR(a); + next = INCPTR(cur); + runHi++; + + // Find end of run, and reverse range if descending + if (CMP(compare, carg, cur, a) < 0) { // Descending + while (runHi < hi && CMP(compare, carg, next, cur) < 0) { + runHi++; + cur = next; + next = INCPTR(next); + } + CALL(reverseRange) (a, runHi, width); + } else { // Ascending + while (runHi < hi && CMP(compare, carg, next, cur) >= 0) { + runHi++; + cur = next; + next = INCPTR(next); + } + } + + (void)width; + return runHi; +} + +/** + * Reverse the specified range of the specified array. + * + * @param a the array in which a range is to be reversed + * @param hi the index after the last element in the range to be reversed + */ +static void NAME(reverseRange) (void *a, size_t hi, size_t width) { + DEFINE_TEMP(t); + char *front = a; + char *back = ELEM(a, hi - 1); + + assert(hi > 0); + + while (front < back) { + ASSIGN(t, front); + ASSIGN(front, back); + ASSIGN(back, t); + front = INCPTR(front); + back = DECPTR(back); + } + (void)width; +} + +/** + * Examines the stack of runs waiting to be merged and merges adjacent runs + * until the stack invariants are reestablished: + * + * 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1] + * 2. runLen[i - 2] > runLen[i - 1] + * + * This method is called each time a new run is pushed onto the stack, + * so the invariants are guaranteed to hold for i < stackSize upon + * entry to the method. + * + * POP: + * Modified according to http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf + * + * and + * + * https://bugs.openjdk.java.net/browse/JDK-8072909 (suggestion 2) + * + */ +static int NAME(mergeCollapse) (struct timsort * ts, size_t width) { + int err = SUCCESS; + + while (ts->stackSize > 1) { + size_t n = ts->stackSize - 2; + struct timsort_run *run = ts->run; + + if ((n > 0 && run[n-1].len <= run[n].len + run[n+1].len) + || (n > 1 && run[n-2].len <= run[n].len + run[n-1].len)) { + if (run[n - 1].len < run[n + 1].len) + n--; + } else if (run[n].len > run[n + 1].len) { + break; /* Invariant is established */ + } + err = CALL(mergeAt) (ts, n, width); + if (err) + break; + } + return err; +} + +/** + * Merges all runs on the stack until only one remains. This method is + * called once, to complete the sort. + */ +static int NAME(mergeForceCollapse) (struct timsort * ts, size_t width) { + int err = SUCCESS; + + while (ts->stackSize > 1) { + size_t n = ts->stackSize - 2; + if (n > 0 && ts->run[n - 1].len < ts->run[n + 1].len) + n--; + err = CALL(mergeAt) (ts, n, width); + if (err) + break; + } + return err; +} + +/** + * Merges the two runs at stack indices i and i+1. Run i must be + * the penultimate or antepenultimate run on the stack. In other words, + * i must be equal to stackSize-2 or stackSize-3. + * + * @param i stack index of the first of the two runs to merge + */ +static int NAME(mergeAt) (struct timsort * ts, size_t i, size_t width) { + void *base1 = ts->run[i].base; + size_t len1 = ts->run[i].len; + void *base2 = ts->run[i + 1].base; + size_t len2 = ts->run[i + 1].len; + size_t k; + + assert(ts->stackSize >= 2); + assert(i == ts->stackSize - 2 || i == ts->stackSize - 3); + assert(len1 > 0 && len2 > 0); + assert(ELEM(base1, len1) == base2); + + /* + * Record the length of the combined runs; if i is the 3rd-last + * run now, also slide over the last run (which isn't involved + * in this merge). The current run (i+1) goes away in any case. + */ + ts->run[i].len = len1 + len2; + if (i == ts->stackSize - 3) { + ts->run[i + 1] = ts->run[i + 2]; + } + ts->stackSize--; + + /* + * Find where the first element of run2 goes in run1. Prior elements + * in run1 can be ignored (because they're already in place). + */ + k = CALL(gallopRight) (base2, base1, len1, 0, CMPARGS(ts->c, ts->carg), width); + base1 = ELEM(base1, k); + len1 -= k; + if (len1 == 0) + return SUCCESS; + + /* + * Find where the last element of run1 goes in run2. Subsequent elements + * in run2 can be ignored (because they're already in place). + */ + len2 = + CALL(gallopLeft) (ELEM(base1, len1 - 1), base2, len2, len2 - 1, + CMPARGS(ts->c, ts->carg), width); + if (len2 == 0) + return SUCCESS; + + // Merge remaining runs, using tmp array with min(len1, len2) elements + if (len1 <= len2) + return CALL(mergeLo) (ts, base1, len1, base2, len2, width); + else + return CALL(mergeHi) (ts, base1, len1, base2, len2, width); +} + +/** + * Locates the position at which to insert the specified key into the + * specified sorted range; if the range contains an element equal to key, + * returns the index of the leftmost equal element. + * + * @param key the key whose insertion point to search for + * @param base the array in which to search + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] < key <= a[b + k], + * pretending that a[b - 1] is minus infinity and a[b + n] is infinity. + * In other words, key belongs at index b + k; or in other words, + * the first k elements of a should precede key, and the last n - k + * should follow it. + */ +static size_t NAME(gallopLeft) (void *key, void *base, size_t len, + size_t hint, CMPPARAMS(compare, carg), + size_t width) { + char *hintp = ELEM(base, hint); + size_t lastOfs = 0; + size_t ofs = 1; + + assert(len > 0 && hint < len); + if (CMP(compare, carg, key, hintp) > 0) { + // Gallop right until a[hint+lastOfs] < key <= a[hint+ofs] + size_t maxOfs = len - hint; + while (ofs < maxOfs + && CMP(compare, carg, key, ELEM(hintp, ofs)) > 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; // eventually this becomes SIZE_MAX + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + lastOfs += hint + 1; // POP: we add 1 here so lastOfs stays non-negative + ofs += hint; + } else { // key <= a[hint] + // Gallop left until a[hint-ofs] < key <= a[hint-lastOfs] + const size_t maxOfs = hint + 1; + size_t tmp; + while (ofs < maxOfs + && CMP(compare, carg, key, ELEM_SUB(hintp, ofs)) <= 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; // no need to check for overflow + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + tmp = lastOfs; + lastOfs = hint + 1 - ofs; // POP: we add 1 here so lastOfs stays non-negative + ofs = hint - tmp; + } + assert(lastOfs <= ofs && ofs <= len); + + /* + * Now a[lastOfs-1] < key <= a[ofs], so key belongs somewhere + * to the right of lastOfs but no farther right than ofs. Do a binary + * search, with invariant a[lastOfs - 1] < key <= a[ofs]. + */ + // lastOfs++; POP: we added 1 above to keep lastOfs non-negative + while (lastOfs < ofs) { + //size_t m = lastOfs + ((ofs - lastOfs) >> 1); + // http://stackoverflow.com/questions/4844165/safe-integer-middle-value-formula + size_t m = (lastOfs & ofs) + ((lastOfs ^ ofs) >> 1); + + if (CMP(compare, carg, key, ELEM(base, m)) > 0) + lastOfs = m + 1; // a[m] < key + else + ofs = m; // key <= a[m] + } + assert(lastOfs == ofs); // so a[ofs - 1] < key <= a[ofs] + (void)width; + return ofs; +} + +/** + * Like gallopLeft, except that if the range contains an element equal to + * key, gallopRight returns the index after the rightmost equal element. + * + * @param key the key whose insertion point to search for + * @param base the array in which to search + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] <= key < a[b + k] + */ +static size_t NAME(gallopRight) (void *key, void *base, size_t len, + size_t hint, CMPPARAMS(compare, carg), + size_t width) { + char *hintp = ELEM(base, hint); + size_t ofs = 1; + size_t lastOfs = 0; + + assert(len > 0 && hint < len); + + if (CMP(compare, carg, key, hintp) < 0) { + // Gallop left until a[hint - ofs] <= key < a[hint - lastOfs] + size_t maxOfs = hint + 1; + size_t tmp; + while (ofs < maxOfs + && CMP(compare, carg, key, ELEM_SUB(hintp, ofs)) < 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; // no need to check for overflow + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + tmp = lastOfs; + lastOfs = hint + 1 - ofs; + ofs = hint - tmp; + } else { // a[hint] <= key + // Gallop right until a[hint + lastOfs] <= key < a[hint + ofs] + size_t maxOfs = len - hint; + while (ofs < maxOfs + && CMP(compare, carg, key, ELEM(hintp, ofs)) >= 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; // no need to check for overflow + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + lastOfs += hint + 1; + ofs += hint; + } + assert(lastOfs <= ofs && ofs <= len); + + /* + * Now a[lastOfs - 1] <= key < a[ofs], so key belongs somewhere to + * the right of lastOfs but no farther right than ofs. Do a binary + * search, with invariant a[lastOfs - 1] <= key < a[ofs]. + */ + while (lastOfs < ofs) { + // size_t m = lastOfs + ((ofs - lastOfs) >> 1); + size_t m = (lastOfs & ofs) + ((lastOfs ^ ofs) >> 1); + + if (CMP(compare, carg, key, ELEM(base, m)) < 0) + ofs = m; // key < a[m] + else + lastOfs = m + 1; // a[m] <= key + } + assert(lastOfs == ofs); // so a[ofs - 1] <= key < a[ofs] + (void)width; + return ofs; +} + +/** + * Merges two adjacent runs in place, in a stable fashion. The first + * element of the first run must be greater than the first element of the + * second run (a[base1] > a[base2]), and the last element of the first run + * (a[base1 + len1-1]) must be greater than all elements of the second run. + * + * For performance, this method should be called only when len1 <= len2; + * its twin, mergeHi should be called if len1 >= len2. (Either method + * may be called if len1 == len2.) + * + * @param base1 first element in first run to be merged + * @param len1 length of first run to be merged (must be > 0) + * @param base2 first element in second run to be merged + * (must be aBase + aLen) + * @param len2 length of second run to be merged (must be > 0) + */ +static int NAME(mergeLo) (struct timsort * ts, void *base1, size_t len1, + void *base2, size_t len2, size_t width) { + + // Copy first run into temp array + void *tmp = ensureCapacity(ts, len1, width); + char *cursor1; + char *cursor2; + char *dest; + comparator compare; // Use local variable for performance +#ifdef IS_TIMSORT_R + void *carg; // Use local variable for performance +#endif + size_t minGallop; // " " " " " + + assert(len1 > 0 && len2 > 0 && ELEM(base1, len1) == base2); + if (!tmp) + return FAILURE; + + // System.arraycopy(a, base1, tmp, 0, len1); + memcpy(tmp, base1, LEN(len1)); // POP: can't overlap + + cursor1 = tmp; // Indexes into tmp array + cursor2 = base2; // Indexes int a + dest = base1; // Indexes int a + + // Move first element of second run and deal with degenerate cases + // a[dest++] = a[cursor2++]; + ASSIGN(dest, cursor2); + dest = INCPTR(dest); + cursor2 = INCPTR(cursor2); + + if (--len2 == 0) { + memcpy(dest, cursor1, LEN(len1)); // POP: can't overlap + return SUCCESS; + } + if (len1 == 1) { + memmove(dest, cursor2, LEN(len2)); // POP: overlaps + + // a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge + ASSIGN(ELEM(dest, len2), cursor1); + return SUCCESS; + } + + compare = ts->c; // Use local variable for performance +#ifdef IS_TIMSORT_R + carg = ts->carg; // Use local variable for performance +#endif + minGallop = ts->minGallop; // " " " " " + + while (1) { + size_t count1 = 0; // Number of times in a row that first run won + size_t count2 = 0; // Number of times in a row that second run won + + /* + * Do the straightforward thing until (if ever) one run starts + * winning consistently. + */ + do { + assert(len1 > 1 && len2 > 0); + if (CMP(compare, carg, cursor2, cursor1) < 0) { + ASSIGN(dest, cursor2); + dest = INCPTR(dest); + cursor2 = INCPTR(cursor2); + count2++; + count1 = 0; + if (--len2 == 0) + goto outer; + if (count2 >= minGallop) + break; + } else { + ASSIGN(dest, cursor1); + dest = INCPTR(dest); + cursor1 = INCPTR(cursor1); + count1++; + count2 = 0; + if (--len1 == 1) + goto outer; + if (count1 >= minGallop) + break; + } + } while (1); // (count1 | count2) < minGallop); + + /* + * One run is winning so consistently that galloping may be a + * huge win. So try that, and continue galloping until (if ever) + * neither run appears to be winning consistently anymore. + */ + do { + assert(len1 > 1 && len2 > 0); + count1 = + CALL(gallopRight) (cursor2, cursor1, len1, 0, + CMPARGS(compare, carg), width); + if (count1 != 0) { + memcpy(dest, cursor1, LEN(count1)); // POP: can't overlap + dest = ELEM(dest, count1); + cursor1 = ELEM(cursor1, count1); + len1 -= count1; + if (len1 <= 1) // len1 == 1 || len1 == 0 + goto outer; + } + ASSIGN(dest, cursor2); + dest = INCPTR(dest); + cursor2 = INCPTR(cursor2); + if (--len2 == 0) + goto outer; + + count2 = + CALL(gallopLeft) (cursor1, cursor2, len2, 0, + CMPARGS(compare, carg), width); + if (count2 != 0) { + memmove(dest, cursor2, LEN(count2)); // POP: might overlap + dest = ELEM(dest, count2); + cursor2 = ELEM(cursor2, count2); + len2 -= count2; + if (len2 == 0) + goto outer; + } + ASSIGN(dest, cursor1); + dest = INCPTR(dest); + cursor1 = INCPTR(cursor1); + if (--len1 == 1) + goto outer; + if (minGallop > 0) + minGallop--; + } while (count1 >= MIN_GALLOP || count2 >= MIN_GALLOP); + minGallop += 2; // Penalize for leaving gallop mode + } // End of "outer" loop +outer: + ts->minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field + + if (len1 == 1) { + assert(len2 > 0); + memmove(dest, cursor2, LEN(len2)); // POP: might overlap + ASSIGN(ELEM(dest, len2), cursor1); // Last elt of run 1 to end of merge + + } else if (len1 == 0) { + errno = EINVAL; // Comparison method violates its general contract + return FAILURE; + } else { + assert(len2 == 0); + assert(len1 > 1); + memcpy(dest, cursor1, LEN(len1)); // POP: can't overlap + } + return SUCCESS; +} + +/** + * Like mergeLo, except that this method should be called only if + * len1 >= len2; mergeLo should be called if len1 <= len2. (Either method + * may be called if len1 == len2.) + * + * @param base1 first element in first run to be merged + * @param len1 length of first run to be merged (must be > 0) + * @param base2 first element in second run to be merged + * (must be aBase + aLen) + * @param len2 length of second run to be merged (must be > 0) + */ +static int NAME(mergeHi) (struct timsort * ts, void *base1, size_t len1, + void *base2, size_t len2, size_t width) { + + // Copy second run into temp array + void *tmp = ensureCapacity(ts, len2, width); + char *cursor1; // Indexes into a + char *cursor2; // Indexes into tmp array + char *dest; // Indexes into a + comparator compare; // Use local variable for performance +#ifdef IS_TIMSORT_R + void *carg; // " " " " " +#endif + size_t minGallop; // " " " " " + + assert(len1 > 0 && len2 > 0 && ELEM(base1, len1) == base2); + if (!tmp) + return FAILURE; + + memcpy(tmp, base2, LEN(len2)); // POP: can't overlap + + cursor1 = ELEM(base1, len1 - 1);// Indexes into a + cursor2 = ELEM(tmp, len2 - 1); // Indexes into tmp array + dest = ELEM(base2, len2 - 1); // Indexes into a + + // Move last element of first run and deal with degenerate cases + // a[dest--] = a[cursor1--]; + ASSIGN(dest, cursor1); + dest = DECPTR(dest); + cursor1 = DECPTR(cursor1); + if (--len1 == 0) { + memcpy(ELEM_SUB(dest, len2 - 1), tmp, LEN(len2)); // POP: can't overlap + return SUCCESS; + } + if (len2 == 1) { + dest = ELEM_SUB(dest, len1); + cursor1 = ELEM_SUB(cursor1, len1); + memmove(ELEM(dest, 1), ELEM(cursor1, 1), LEN(len1)); // POP: overlaps + // a[dest] = tmp[cursor2]; + ASSIGN(dest, cursor2); + return SUCCESS; + } + + compare = ts->c; // Use local variable for performance +#ifdef IS_TIMSORT_R + carg = ts->carg; // Use local variable for performance +#endif + minGallop = ts->minGallop; // " " " " " + + while (1) { + size_t count1 = 0; // Number of times in a row that first run won + size_t count2 = 0; // Number of times in a row that second run won + + /* + * Do the straightforward thing until (if ever) one run + * appears to win consistently. + */ + do { + assert(len1 > 0 && len2 > 1); + if (CMP(compare, carg, cursor2, cursor1) < 0) { + ASSIGN(dest, cursor1); + dest = DECPTR(dest); + cursor1 = DECPTR(cursor1); + count1++; + count2 = 0; + if (--len1 == 0) + goto outer; + } else { + ASSIGN(dest, cursor2); + dest = DECPTR(dest); + cursor2 = DECPTR(cursor2); + count2++; + count1 = 0; + if (--len2 == 1) + goto outer; + } + } while ((count1 | count2) < minGallop); + + /* + * One run is winning so consistently that galloping may be a + * huge win. So try that, and continue galloping until (if ever) + * neither run appears to be winning consistently anymore. + */ + do { + assert(len1 > 0 && len2 > 1); + count1 = + len1 - CALL(gallopRight) (cursor2, base1, + len1, len1 - 1, + CMPARGS(compare, carg), + width); + if (count1 != 0) { + dest = ELEM_SUB(dest, count1); + cursor1 = ELEM_SUB(cursor1, count1); + len1 -= count1; + memmove(INCPTR(dest), INCPTR(cursor1), + LEN(count1)); // POP: might overlap + if (len1 == 0) + goto outer; + } + ASSIGN(dest, cursor2); + dest = DECPTR(dest); + cursor2 = DECPTR(cursor2); + if (--len2 == 1) + goto outer; + + count2 = + len2 - CALL(gallopLeft) (cursor1, tmp, len2, + len2 - 1, CMPARGS(compare, carg), + width); + if (count2 != 0) { + dest = ELEM_SUB(dest, count2); + cursor2 = ELEM_SUB(cursor2, count2); + len2 -= count2; + memcpy(INCPTR(dest), INCPTR(cursor2), LEN(count2)); // POP: can't overlap + if (len2 <= 1) // len2 == 1 || len2 == 0 + goto outer; + } + ASSIGN(dest, cursor1); + dest = DECPTR(dest); + cursor1 = DECPTR(cursor1); + if (--len1 == 0) + goto outer; + if (minGallop > 0) + minGallop--; + } while (count1 >= MIN_GALLOP || count2 >= MIN_GALLOP); + minGallop += 2; // Penalize for leaving gallop mode + } // End of "outer" loop +outer: + ts->minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field + + if (len2 == 1) { + assert(len1 > 0); + dest = ELEM_SUB(dest, len1); + cursor1 = ELEM_SUB(cursor1, len1); + memmove(INCPTR(dest), INCPTR(cursor1), LEN(len1)); // POP: might overlap + // a[dest] = tmp[cursor2]; // Move first elt of run2 to front of merge + ASSIGN(dest, cursor2); + } else if (len2 == 0) { + errno = EINVAL; // Comparison method violates its general contract + return FAILURE; + } else { + assert(len1 == 0); + assert(len2 > 0); + memcpy(ELEM_SUB(dest, len2 - 1), tmp, LEN(len2)); // POP: can't overlap + } + + return SUCCESS; +} diff --git a/src/timsort/timsort.c b/src/timsort/timsort.c new file mode 100644 index 000000000..67163b431 --- /dev/null +++ b/src/timsort/timsort.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2011 Patrick O. Perry + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include // assert +#include // EINVAL +#if defined(_MSC_VER) +# include // _alloca +#endif +#include // size_t, NULL +#include // malloc, free +#include // memcpy, memmove +#include "timsort.h" + +/** + * This is the minimum sized sequence that will be merged. Shorter + * sequences will be lengthened by calling binarySort. If the entire + * array is less than this length, no merges will be performed. + * + * This constant should be a power of two. It was 64 in Tim Peter's C + * implementation, but 32 was empirically determined to work better in + * [Android's Java] implementation. In the unlikely event that you set + * this constant to be a number that's not a power of two, you'll need + * to change the {@link #minRunLength} computation. + * + * If you decrease this constant, you must change the stackLen + * computation in the TimSort constructor, or you risk an + * ArrayOutOfBounds exception. See listsort.txt for a discussion + * of the minimum stack length required as a function of the length + * of the array being sorted and the minimum merge sequence length. + */ +#define MIN_MERGE 32 + +/** + * When we get into galloping mode, we stay there until both runs win less + * often than MIN_GALLOP consecutive times. + */ +#define MIN_GALLOP 7 + +/** + * Maximum initial size of tmp array, which is used for merging. The array + * can grow to accommodate demand. + * + * Unlike Tim's original C version, we do not allocate this much storage + * when sorting smaller arrays. This change was required for performance. + */ +#define INITIAL_TMP_STORAGE_LENGTH 256 + +/** + * Maximum stack size. This depends on MIN_MERGE and sizeof(size_t). + */ +#define MAX_STACK 85 + +/** + * Define MALLOC_STACK if you want to allocate the run stack on the heap. + * Otherwise, 2* MAX_STACK * sizeof(size_t) ~ 1.3K gets reserved on the + * call stack. + */ +/* #undef MALLOC_STACK */ + +#if defined(_MSC_VER) +# define DEFINE_TEMP(temp) void *temp = _alloca(WIDTH) +#else +# define DEFINE_TEMP(temp) char temp[WIDTH] +#endif + +#define ASSIGN(x, y) memcpy(x, y, WIDTH) +#define INCPTR(x) ((void *)((char *)(x) + WIDTH)) +#define DECPTR(x) ((void *)((char *)(x) - WIDTH)) +#define ELEM(a,i) ((char *)(a) + (i) * WIDTH) +#define ELEM_SUB(a,i) ((char *)(a) - (i) * WIDTH) +#define LEN(n) ((n) * WIDTH) + +#define MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define SUCCESS 0 +#define FAILURE (-1) + +#define CONCAT(x, y) x ## _ ## y +#define MAKE_STR(x, y) CONCAT(x,y) +#define NAME(x) MAKE_STR(x, WIDTH) +#define CALL(x) NAME(x) + + +#ifdef IS_TIMSORT_R +/* + * Note order of elements to comparator matches that of C11 qsort_s, + * not BSD qsort_r or Windows qsort_s + */ +typedef int (*comparator) (const void *x, const void *y, void *thunk); +#define CMPPARAMS(compar, thunk) comparator compar, void *thunk +#define CMPARGS(compar, thunk) (compar), (thunk) +#define CMP(compar, thunk, x, y) (compar((x), (y), (thunk))) +#define TIMSORT timsort_r + +#else + +typedef int (*comparator) (const void *x, const void *y); +#define CMPPARAMS(compar, thunk) comparator compar +#define CMPARGS(compar, thunk) (compar) +#define CMP(compar, thunk, x, y) (compar((x), (y))) +#define TIMSORT timsort + +#endif /* IS_TIMSORT_R */ + +struct timsort_run { + void *base; + size_t len; +}; + +struct timsort { + /** + * The array being sorted. + */ + void *a; + size_t a_length; + + /** + * The comparator for this sort. + */ + comparator c; +#ifdef IS_TIMSORT_R + void *carg; +#endif + + /** + * This controls when we get *into* galloping mode. It is initialized + * to MIN_GALLOP. The mergeLo and mergeHi methods nudge it higher for + * random data, and lower for highly structured data. + */ + size_t minGallop; + + /** + * Temp storage for merges. + */ + void *tmp; + size_t tmp_length; + + /** + * A stack of pending runs yet to be merged. Run i starts at + * address base[i] and extends for len[i] elements. It's always + * true (so long as the indices are in bounds) that: + * + * runBase[i] + runLen[i] == runBase[i + 1] + * + * so we could cut the storage for this, but it's a minor amount, + * and keeping all the info explicit simplifies the code. + */ + size_t stackSize; // Number of pending runs on stack + size_t stackLen; // maximum stack size +#ifdef MALLOC_STACK + struct timsort_run *run; +#else + struct timsort_run run[MAX_STACK]; +#endif +}; + +static int timsort_init(struct timsort *ts, void *a, size_t len, + CMPPARAMS(c, carg), + size_t width); +static void timsort_deinit(struct timsort *ts); +static size_t minRunLength(size_t n); +static void pushRun(struct timsort *ts, void *runBase, size_t runLen); +static void *ensureCapacity(struct timsort *ts, size_t minCapacity, + size_t width); + +/** + * Creates a TimSort instance to maintain the state of an ongoing sort. + * + * @param a the array to be sorted + * @param nel the length of the array + * @param c the comparator to determine the order of the sort + * @param width the element width + */ +static int timsort_init(struct timsort *ts, void *a, size_t len, + CMPPARAMS(c, carg), + size_t width) +{ + int err = 0; + + assert(ts); + assert(a || !len); + assert(c); + assert(width); + + ts->minGallop = MIN_GALLOP; + ts->stackSize = 0; + + ts->a = a; + ts->a_length = len; + ts->c = c; +#ifdef IS_TIMSORT_R + ts->carg = carg; +#endif + + // Allocate temp storage (which may be increased later if necessary) + ts->tmp_length = (len < 2 * INITIAL_TMP_STORAGE_LENGTH ? + len >> 1 : INITIAL_TMP_STORAGE_LENGTH); + if (ts->tmp_length) { + ts->tmp = malloc(ts->tmp_length * width); + err |= ts->tmp == NULL; + } else { + ts->tmp = NULL; + } + + /* + * Allocate runs-to-be-merged stack (which cannot be expanded). The + * stack length requirements are described in listsort.txt. The C + * version always uses the same stack length (85), but this was + * measured to be too expensive when sorting "mid-sized" arrays (e.g., + * 100 elements) in Java. Therefore, we use smaller (but sufficiently + * large) stack lengths for smaller arrays. The "magic numbers" in the + * computation below must be changed if MIN_MERGE is decreased. See + * the MIN_MERGE declaration above for more information. + */ + + /* POP: + * In listsort.txt, Tim argues that the run lengths form a decreasing + * sequence, and each run length is greater than the previous two. + * Thus, lower bounds on the minimum runLen numbers on the stack are: + * + * [ 1 = b[1] + * , minRun = b[2] + * , 1 * minRun + 2 = b[3] + * , 2 * minRun + 3 = b[4] + * , 3 * minRun + 6 = b[5] + * , ... + * ], + * + * Moreover, minRun >= MIN_MERGE / 2. Also, note that the sum of the + * run lenghts is less than or equal to the length of the array. + * + * Let s be the stack length and n be the array length. If s >= 2, then n >= b[1] + b[2]. + * More generally, if s >= m, then n >= b[1] + b[2] + ... + b[m] = B[m]. Conversely, if + * n < B[m], then s < m. + * + * In Haskell, we can compute the bin sizes using the fibonacci numbers + * + * fibs = 1:1:(zipWith (+) fibs (tail fibs)) + * + * cumSums a = case a of { [] -> [] ; (x:xs) -> x:(map (x+) (cumSums xs)) } + * + * fibSums = cumSums fibs + * + * binSizes minRun = ([ 1, minRun, minRun + 2 ] + * ++ [ (1 + minRun) * (fibs !! (i+2)) + * + fibSums !! (i+1) - fibs !! i | i <- [0..] ]) + * + * arraySizes minRun = cumSums (binSizes minRun) + * + * We these funcitons, we can compute a table with minRun = MIN_MERGE / 2 = 16: + * + * m B[m] + * --------------------------- + * 1 17 + * 2 35 + * 3 70 + * 4 124 + * 5 214 + * 6 359 + * 11 4220 + * 17 76210 # > 2^16 - 1 + * 40 4885703256 # > 2^32 - 1 + * 86 20061275507500957239 # > 2^64 - 1 + * + * If len < B[m], then stackLen < m: + */ +#ifdef MALLOC_STACK + ts->stackLen = (len < 359 ? 5 + : len < 4220 ? 10 + : len < 76210 ? 16 : len < 4885703256ULL ? 39 : 85); + + /* Note that this is slightly more liberal than in the Java + * implementation. The discrepancy might be because the Java + * implementation uses a less accurate lower bound. + */ + //stackLen = (len < 120 ? 5 : len < 1542 ? 10 : len < 119151 ? 19 : 40); + + ts->run = malloc(ts->stackLen * sizeof(ts->run[0])); + err |= ts->run == NULL; +#else + ts->stackLen = MAX_STACK; +#endif + + if (!err) { + return SUCCESS; + } else { + timsort_deinit(ts); + return FAILURE; + } +} + +static void timsort_deinit(struct timsort *ts) +{ + free(ts->tmp); +#ifdef MALLOC_STACK + free(ts->run); +#endif +} + +/** + * Returns the minimum acceptable run length for an array of the specified + * length. Natural runs shorter than this will be extended with + * {@link #binarySort}. + * + * Roughly speaking, the computation is: + * + * If n < MIN_MERGE, return n (it's too small to bother with fancy stuff). + * Else if n is an exact power of 2, return MIN_MERGE/2. + * Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k + * is close to, but strictly less than, an exact power of 2. + * + * For the rationale, see listsort.txt. + * + * @param n the length of the array to be sorted + * @return the length of the minimum run to be merged + */ +static size_t minRunLength(size_t n) +{ + size_t r = 0; // Becomes 1 if any 1 bits are shifted off + while (n >= MIN_MERGE) { + r |= (n & 1); + n >>= 1; + } + return n + r; +} + +/** + * Pushes the specified run onto the pending-run stack. + * + * @param runBase index of the first element in the run + * @param runLen the number of elements in the run + */ +static void pushRun(struct timsort *ts, void *runBase, size_t runLen) +{ + assert(ts->stackSize < ts->stackLen); + + ts->run[ts->stackSize].base = runBase; + ts->run[ts->stackSize].len = runLen; + ts->stackSize++; +} + +/** + * Ensures that the external array tmp has at least the specified + * number of elements, increasing its size if necessary. The size + * increases exponentially to ensure amortized linear time complexity. + * + * @param minCapacity the minimum required capacity of the tmp array + * @return tmp, whether or not it grew + */ +static void *ensureCapacity(struct timsort *ts, size_t minCapacity, + size_t width) +{ + if (ts->tmp_length < minCapacity) { + // Compute smallest power of 2 > minCapacity + size_t newSize = minCapacity; + newSize |= newSize >> 1; + newSize |= newSize >> 2; + newSize |= newSize >> 4; + newSize |= newSize >> 8; + newSize |= newSize >> 16; + if (sizeof(newSize) > 4) + newSize |= newSize >> 32; + + newSize++; + newSize = MIN(newSize, ts->a_length >> 1); + if (newSize == 0) { // (overflow) Not bloody likely! + newSize = minCapacity; + } + + free(ts->tmp); + ts->tmp_length = newSize; + ts->tmp = malloc(ts->tmp_length * width); + } + + return ts->tmp; +} + +#define WIDTH 4 +#include "timsort-impl.h" +#undef WIDTH + +#define WIDTH 8 +#include "timsort-impl.h" +#undef WIDTH + +#define WIDTH 16 +#include "timsort-impl.h" +#undef WIDTH + +#define WIDTH width +#include "timsort-impl.h" +#undef WIDTH + + +int TIMSORT(void *a, size_t nel, size_t width, CMPPARAMS(c, carg)) +{ + switch (width) { + case 4: + return timsort_4(a, nel, width, CMPARGS(c, carg)); + case 8: + return timsort_8(a, nel, width, CMPARGS(c, carg)); + case 16: + return timsort_16(a, nel, width, CMPARGS(c, carg)); + default: + return timsort_width(a, nel, width, CMPARGS(c, carg)); + } +} diff --git a/src/timsort/timsort.h b/src/timsort/timsort.h new file mode 100644 index 000000000..8a77e788a --- /dev/null +++ b/src/timsort/timsort.h @@ -0,0 +1,65 @@ +#ifndef TIMSORT_H +#define TIMSORT_H +/* + * Copyright (C) 2011 Patrick O. Perry + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A stable, adaptive, iterative mergesort that requires far fewer than + * n lg(n) comparisons when running on partially sorted arrays, while + * offering performance comparable to a traditional mergesort when run + * on random arrays. Like all proper mergesorts, this sort is stable and + * runs O(n log n) time (worst case). In the worst case, this sort requires + * temporary storage space for n/2 object references; in the best case, + * it requires only a small constant amount of space. + * + * This implementation was adapted from Josh Bloch's Java implementation of + * Tim Peters's list sort for Python, which is described in detail here: + * + * http://svn.python.org/projects/python/trunk/Objects/listsort.txt + * + * Tim's C code may be found here: + * + * http://svn.python.org/projects/python/trunk/Objects/listobject.c + * + * Josh's (Apache 2.0 Licenced) Java code may be found here: + * + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/TimSort.java?view=co + * + * The underlying techniques are described in this paper (and may have + * even earlier origins): + * + * "Optimistic Sorting and Information Theoretic Complexity" + * Peter McIlroy + * SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), + * pp 467-474, Austin, Texas, 25-27 January 1993. + * + * While the API to this class consists solely of static methods, it is + * (privately) instantiable; a TimSort instance holds the state of an ongoing + * sort, assuming the input array is large enough to warrant the full-blown + * TimSort. Small arrays are sorted in place, using a binary insertion sort. + * + * @author Josh Bloch + * @author Patrick O. Perry + */ +int timsort(void *base, size_t nel, size_t width, + int (*compar) (const void *, const void *)); + +int timsort_r(void *base, size_t nel, size_t width, + int (*compar) (const void *, const void *, void *), + void *context); + +#endif /* TIMSORT_H */ diff --git a/src/timsort/timsort_r.c b/src/timsort/timsort_r.c new file mode 100644 index 000000000..5b2450579 --- /dev/null +++ b/src/timsort/timsort_r.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2013 Patrick O. Perry + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define IS_TIMSORT_R +#include "timsort.c" diff --git a/src/uthash/License.txt b/src/uthash/License.txt index e75a243af..94661955f 100644 --- a/src/uthash/License.txt +++ b/src/uthash/License.txt @@ -1,4 +1,4 @@ -Copyright (c) 2005-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2005-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -18,4 +18,3 @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/src/uthash/utarray.h b/src/uthash/utarray.h index 4f80c4484..5eb27696a 100644 --- a/src/uthash/utarray.h +++ b/src/uthash/utarray.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2008-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -38,11 +38,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define UTARRAY_UNUSED #endif -#ifdef oom -#error "The name of macro 'oom' has been changed to 'utarray_oom'. Please update your code." -#define utarray_oom() oom() -#endif - #ifndef utarray_oom #define utarray_oom() exit(-1) #endif @@ -141,6 +136,12 @@ typedef struct { (a)->i++; \ } while(0) +#define utarray_replace(a,p,j) do { \ + if ((a)->icd.dtor) { (a)->icd.dtor(_utarray_eltptr(a,j)); } \ + if ((a)->icd.copy) { (a)->icd.copy(_utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); } \ +} while(0) + #define utarray_inserta(a,w,j) do { \ if (utarray_len(w) == 0) break; \ if ((j) > (a)->i) utarray_resize(a,j); \ @@ -234,7 +235,17 @@ typedef struct { static void utarray_str_cpy(void *dst, const void *src) { char *const *srcc = (char *const *)src; char **dstc = (char**)dst; - *dstc = (*srcc == NULL) ? NULL : _strdup(*srcc); + if (*srcc == NULL) { + *dstc = NULL; + } else { + size_t const len = strlen(*srcc) + 1; + *dstc = (char*)malloc(len); + if (*dstc == NULL) { + utarray_oom(); + } else { + strcpy_s(*dstc, len, *srcc); + } + } } static void utarray_str_dtor(void *elt) { char **eltc = (char**)elt; diff --git a/src/uthash/uthash.h b/src/uthash/uthash.h index 6dd37fa6f..9d57c7ef4 100644 --- a/src/uthash/uthash.h +++ b/src/uthash/uthash.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2003-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,12 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /* ptrdiff_t */ #include /* exit */ -#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT -/* This codepath is provided for backward compatibility, but I plan to remove it. */ -#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" -typedef unsigned int uint32_t; -typedef unsigned char uint8_t; -#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT +#if defined(HASH_NO_STDINT) && HASH_NO_STDINT +/* The user doesn't have , and must figure out their own way + to provide definitions for uint8_t and uint32_t. */ #else #include /* uint8_t, uint32_t */ #endif @@ -51,6 +48,8 @@ typedef unsigned char uint8_t; #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define DECLTYPE(x) (__typeof(x)) #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #else /* GNU, Sun and other compilers */ @@ -157,7 +156,7 @@ do { if (head) { \ unsigned _hf_bkt; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ } \ } \ @@ -194,7 +193,7 @@ do { } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) ((bv[(idx)/8U] & (1U << ((idx)%8U))) != 0) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) @@ -206,7 +205,7 @@ do { #define HASH_BLOOM_MAKE(tbl,oomed) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_TEST(tbl,hashv) 1 #define HASH_BLOOM_BYTELEN 0U #endif @@ -450,7 +449,7 @@ do { #define HASH_DELETE_HH(hh,head,delptrhh) \ do { \ - struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + const struct UT_hash_handle *_hd_hh_del = (delptrhh); \ if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl->buckets, \ @@ -593,7 +592,9 @@ do { /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx + * (archive link: https://archive.is/Ivcan ) + */ #define HASH_SAX(key,keylen,hashv) \ do { \ unsigned _sx_i; \ diff --git a/src/uthash/utlist.h b/src/uthash/utlist.h index 074b6192b..19426887d 100644 --- a/src/uthash/utlist.h +++ b/src/uthash/utlist.h @@ -1,5 +1,5 @@ -/* -Copyright (c) 2007-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +/* +Copyright (c) 2007-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 3. CDL_ macros: circular doubly-linked lists. * * To use singly-linked lists, your structure must have a "next" pointer. - * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * To use doubly-linked lists, your structure must have "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. * * ----------------.EXAMPLE ------------------------- @@ -70,6 +70,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define LDECLTYPE(x) __typeof(x) #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #else /* GNU, Sun and other compilers */ @@ -444,18 +446,24 @@ do { // >>>>>>>> begin patch: search in ordered list >>>>>>>> -#define LL_SEARCH_ORDERED(head,prv,out,elt,cmp) \ - LL_SEARCH_ORDERED2(head,prv,out,elt,cmp,next) +#define LL_SEARCH_ORDERED(head, prv, out, elt, cmp) \ + LL_SEARCH_ORDERED2(head, prv, out, elt, cmp, next) -#define LL_SEARCH_ORDERED2(head,prv,out,elt,cmp,next) \ -do { \ - LL_FOREACH2(head,out,next) { \ - int const res = (cmp(out,elt)); \ - if (res == 0) { break; } \ - if (res > 0) { (out) = NULL; break; } \ - (prv) = (out); \ - } \ -} while (0) +#define LL_SEARCH_ORDERED2(head, prv, out, elt, cmp, next) \ + do { \ + LL_FOREACH2(head, out, next) \ + { \ + int const res = (cmp(out, elt)); \ + if (res == 0) { \ + break; \ + } \ + if (res > 0) { \ + (out) = NULL; \ + break; \ + } \ + (prv) = (out); \ + } \ + } while (0) // <<<<<<<< end patch: search in ordered list <<<<<<<<<< @@ -726,7 +734,8 @@ do { assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ - } else if ((del)==(head)) { \ + } else if ((del) == (head)) { \ + assert((del)->next != NULL); \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ @@ -766,8 +775,6 @@ do { #define DL_SEARCH LL_SEARCH #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 -#define DL_SEARCH_ORDERED LL_SEARCH_ORDERED -#define DL_SEARCH_ORDERED2 LL_SEARCH_ORDERED2 #define DL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ diff --git a/src/uthash/utringbuffer.h b/src/uthash/utringbuffer.h index b116fa3fd..89b566b8e 100644 --- a/src/uthash/utringbuffer.h +++ b/src/uthash/utringbuffer.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2015-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/uthash/utstack.h b/src/uthash/utstack.h index e0b05d5f0..d71bcdb12 100644 --- a/src/uthash/utstack.h +++ b/src/uthash/utstack.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2018-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2018-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/uthash/utstring.h b/src/uthash/utstring.h index 0dce59c85..264d5b4f8 100644 --- a/src/uthash/utstring.h +++ b/src/uthash/utstring.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2008-2025, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -32,12 +32,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #ifdef __GNUC__ #define UTSTRING_UNUSED __attribute__((__unused__)) #else -#define UTSTRING_UNUSED inline +#define UTSTRING_UNUSED #endif #ifdef oom @@ -68,22 +67,17 @@ do { \ } \ } while(0) -#define utstring_sanitize(s) \ +#define utstring_init(s) \ do { \ - (s)->i = strlen((s)->d); \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ } while(0) #define utstring_done(s) \ do { \ if ((s)->d != NULL) free((s)->d); \ - (s)->d = NULL; (s)->n = 0; (s)->i = 0; \ -} while(0) - -#define utstring_init(s) \ -do { \ - utstring_done(s); \ - utstring_reserve(s,128); \ - (s)->d[0] = '\0'; \ + (s)->n = 0; \ } while(0) #define utstring_free(s) \ @@ -98,16 +92,9 @@ do { \ if (!(s)) { \ utstring_oom(); \ } \ - (s)->d = NULL; \ utstring_init(s); \ } while(0) -#define utstring_clear(s) \ -do { \ - (s)->d[0] = '\0'; \ - (s)->i = 0; \ -} while(0) - #define utstring_renew(s) \ do { \ if (s) { \ @@ -117,33 +104,34 @@ do { \ } \ } while(0) +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ + (s)->d[0] = '\0'; \ +} while(0) + #define utstring_bincpy(s,b,l) \ do { \ utstring_reserve((s),(l)+1); \ - if (l) memcpy(&((s)->d[(s)->i]), b, l); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ (s)->i += (l); \ (s)->d[(s)->i]='\0'; \ } while(0) -#define utstring_concat(dst,src) \ -do { \ - utstring_reserve((dst),((src)->i)+1); \ - if ((src)->i) memcpy(&((dst)->d[(dst)->i]), (src)->d, (src)->i); \ - (dst)->i += (src)->i; \ - (dst)->d[(dst)->i]='\0'; \ +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve((dst),((src)->i)+1); \ + if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ + (dst)->i += (src)->i; \ + (dst)->d[(dst)->i]='\0'; \ } while(0) -#define utstring_is_empty(s) (!((s)->d) || ((s)->d[0] == '\0')) - #define utstring_len(s) ((s)->i) #define utstring_body(s) ((s)->d) -#define utstring_alloc_len(s) ((s)->n) - - UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { - ptrdiff_t n; + int n; va_list cp; for (;;) { #ifdef _WIN32 @@ -151,10 +139,10 @@ UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va #else va_copy(cp, ap); #endif - n = (ptrdiff_t)vsnprintf(&s->d[s->i], s->n - s->i, fmt, cp); + n = vsnprintf(&s->d[s->i], s->n-s->i, fmt, cp); va_end(cp); - if ((n > -1) && (n < (ptrdiff_t)(s->n - s->i))) { + if ((n > -1) && ((size_t) n < (s->n-s->i))) { s->i += n; return; } @@ -167,7 +155,7 @@ UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va #ifdef __GNUC__ /* support printf format checking (2=the format string, 3=start of varargs) */ static void utstring_printf(UT_string *s, const char *fmt, ...) - __attribute__ (( format( printf, 2, 3) )); + __attribute__((format(printf, 2, 3))); #endif UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) { va_list ap; @@ -183,14 +171,14 @@ UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) UTSTRING_UNUSED static void _utstring_BuildTable( const char *P_Needle, size_t P_NeedleLen, - ptrdiff_t* P_KMP_Table) + long *P_KMP_Table) { - ptrdiff_t i, j; + long i, j; i = 0; j = i - 1; P_KMP_Table[i] = j; - while (i < (ptrdiff_t)P_NeedleLen) + while (i < (long) P_NeedleLen) { while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) { @@ -198,7 +186,7 @@ UTSTRING_UNUSED static void _utstring_BuildTable( } i++; j++; - if (i < (ptrdiff_t)P_NeedleLen) + if (i < (long) P_NeedleLen) { if (P_Needle[i] == P_Needle[j]) { @@ -223,16 +211,16 @@ UTSTRING_UNUSED static void _utstring_BuildTable( UTSTRING_UNUSED static void _utstring_BuildTableR( const char *P_Needle, size_t P_NeedleLen, - ptrdiff_t* P_KMP_Table) + long *P_KMP_Table) { - ptrdiff_t i, j; + long i, j; i = P_NeedleLen - 1; j = i + 1; P_KMP_Table[i + 1] = j; while (i >= 0) { - while ((j < (ptrdiff_t)P_NeedleLen) && (P_Needle[i] != P_Needle[j])) + while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) { j = P_KMP_Table[j + 1]; } @@ -260,19 +248,19 @@ UTSTRING_UNUSED static void _utstring_BuildTableR( /* Search data from left to right. ( Multiple search mode. ) */ -UTSTRING_UNUSED static ptrdiff_t _utstring_find( +UTSTRING_UNUSED static long _utstring_find( const char *P_Haystack, size_t P_HaystackLen, const char *P_Needle, size_t P_NeedleLen, - ptrdiff_t* P_KMP_Table) + const long *P_KMP_Table) { - ptrdiff_t i, j; - ptrdiff_t V_FindPosition = -1; + long i, j; + long V_FindPosition = -1; /* Search from left to right. */ i = j = 0; - while ((j < (ptrdiff_t)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen)) + while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) { while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) { @@ -280,7 +268,7 @@ UTSTRING_UNUSED static ptrdiff_t _utstring_find( } i++; j++; - if (i >= (ptrdiff_t)P_NeedleLen) + if (i >= (int)P_NeedleLen) { /* Found. */ V_FindPosition = j - i; @@ -293,22 +281,22 @@ UTSTRING_UNUSED static ptrdiff_t _utstring_find( /* Search data from right to left. ( Multiple search mode. ) */ -UTSTRING_UNUSED static ptrdiff_t _utstring_findR( +UTSTRING_UNUSED static long _utstring_findR( const char *P_Haystack, size_t P_HaystackLen, const char *P_Needle, size_t P_NeedleLen, - ptrdiff_t* P_KMP_Table) + const long *P_KMP_Table) { - ptrdiff_t i, j; - ptrdiff_t V_FindPosition = -1; + long i, j; + long V_FindPosition = -1; /* Search from right to left. */ j = (P_HaystackLen - 1); i = (P_NeedleLen - 1); while ( (j >= 0) && (j >= i) ) { - while ((i < (ptrdiff_t)P_NeedleLen) && (P_Needle[i] != P_Haystack[j])) + while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) { i = P_KMP_Table[i + 1]; } @@ -327,16 +315,16 @@ UTSTRING_UNUSED static ptrdiff_t _utstring_findR( /* Search data from left to right. ( One time search mode. ) */ -UTSTRING_UNUSED static ptrdiff_t utstring_find( - UT_string *s, - ptrdiff_t P_StartPosition, /* Start from 0. -1 means last position. */ +UTSTRING_UNUSED static long utstring_find( + const UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ const char *P_Needle, size_t P_NeedleLen) { - ptrdiff_t V_StartPosition; - ptrdiff_t V_HaystackLen; - ptrdiff_t* V_KMP_Table; - ptrdiff_t V_FindPosition = -1; + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; if (P_StartPosition < 0) { @@ -347,9 +335,9 @@ UTSTRING_UNUSED static ptrdiff_t utstring_find( V_StartPosition = P_StartPosition; } V_HaystackLen = s->i - V_StartPosition; - if ((V_HaystackLen >= (ptrdiff_t)P_NeedleLen) && (P_NeedleLen > 0)) + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) { - V_KMP_Table = (ptrdiff_t*)malloc(sizeof(ptrdiff_t) * (P_NeedleLen + 1)); + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); if (V_KMP_Table != NULL) { _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); @@ -373,16 +361,16 @@ UTSTRING_UNUSED static ptrdiff_t utstring_find( /* Search data from right to left. ( One time search mode. ) */ -UTSTRING_UNUSED static ptrdiff_t utstring_findR( - UT_string *s, - ptrdiff_t P_StartPosition, /* Start from 0. -1 means last position. */ +UTSTRING_UNUSED static long utstring_findR( + const UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ const char *P_Needle, size_t P_NeedleLen) { - ptrdiff_t V_StartPosition; - ptrdiff_t V_HaystackLen; - ptrdiff_t* V_KMP_Table; - ptrdiff_t V_FindPosition = -1; + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; if (P_StartPosition < 0) { @@ -393,9 +381,9 @@ UTSTRING_UNUSED static ptrdiff_t utstring_findR( V_StartPosition = P_StartPosition; } V_HaystackLen = V_StartPosition + 1; - if ((V_HaystackLen >= (ptrdiff_t)P_NeedleLen) && (P_NeedleLen > 0)) + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) { - V_KMP_Table = (ptrdiff_t*)malloc(sizeof(ptrdiff_t) * (P_NeedleLen + 1)); + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); if (V_KMP_Table != NULL) { _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); @@ -416,21 +404,4 @@ UTSTRING_UNUSED static ptrdiff_t utstring_findR( * end substring search functions * ******************************************************************************/ - -UTSTRING_UNUSED static void utstring_setw(UT_string* s, const wchar_t* wch) -{ - int const len = WideCharToMultiByte(CP_UTF8, 0, wch, -1, NULL, 0, NULL, NULL); - utstring_clear(s); - if ((s)->n < len) { utstring_reserve(s, len - (s)->n); } - WideCharToMultiByte(CP_UTF8, 0, wch, -1, (s)->d, len, NULL, NULL); - (s)->i = strlen((s)->d); -} - - -UTSTRING_UNUSED static size_t utstring_getw(UT_string* s, wchar_t* wch, size_t count) -{ - return (size_t) MultiByteToWideChar(CP_UTF8, 0, utstring_body(s), -1, wch, (int)count); -} - - #endif /* UTSTRING_H */ From 9efe9b4234bdc0f8af0795364bb04f7e6469e7ca Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Fri, 6 Mar 2026 14:09:29 +0100 Subject: [PATCH 2/2] fix: warnings thrown as errors --- src/timsort/timsort-impl.h | 10 +++++----- src/timsort/timsort.c | 7 +++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/timsort/timsort-impl.h b/src/timsort/timsort-impl.h index eb81c183d..2b6f42397 100644 --- a/src/timsort/timsort-impl.h +++ b/src/timsort/timsort-impl.h @@ -308,7 +308,7 @@ static int NAME(mergeForceCollapse) (struct timsort * ts, size_t width) { /** * Merges the two runs at stack indices i and i+1. Run i must be - * the penultimate or antepenultimate run on the stack. In other words, + * the penultimate or ante-penultimate run on the stack. In other words, * i must be equal to stackSize-2 or stackSize-3. * * @param i stack index of the first of the two runs to merge @@ -580,7 +580,7 @@ static int NAME(mergeLo) (struct timsort * ts, void *base1, size_t len1, #endif minGallop = ts->minGallop; // " " " " " - while (1) { + for(;;) { size_t count1 = 0; // Number of times in a row that first run won size_t count2 = 0; // Number of times in a row that second run won @@ -588,7 +588,7 @@ static int NAME(mergeLo) (struct timsort * ts, void *base1, size_t len1, * Do the straightforward thing until (if ever) one run starts * winning consistently. */ - do { + for (;;) { assert(len1 > 1 && len2 > 0); if (CMP(compare, carg, cursor2, cursor1) < 0) { ASSIGN(dest, cursor2); @@ -611,7 +611,7 @@ static int NAME(mergeLo) (struct timsort * ts, void *base1, size_t len1, if (count1 >= minGallop) break; } - } while (1); // (count1 | count2) < minGallop); + }; //~ do {...} while ((count1 | count2) < minGallop); /* * One run is winning so consistently that galloping may be a @@ -736,7 +736,7 @@ static int NAME(mergeHi) (struct timsort * ts, void *base1, size_t len1, #endif minGallop = ts->minGallop; // " " " " " - while (1) { + for(;;) { size_t count1 = 0; // Number of times in a row that first run won size_t count2 = 0; // Number of times in a row that second run won diff --git a/src/timsort/timsort.c b/src/timsort/timsort.c index 67163b431..308602278 100644 --- a/src/timsort/timsort.c +++ b/src/timsort/timsort.c @@ -371,8 +371,11 @@ static void *ensureCapacity(struct timsort *ts, size_t minCapacity, newSize |= newSize >> 4; newSize |= newSize >> 8; newSize |= newSize >> 16; - if (sizeof(newSize) > 4) - newSize |= newSize >> 32; + //if (sizeof(newSize) > 4) + // newSize |= newSize >> 32; +#if (SIZE_MAX > 0xFFFFFFFFUL) + newSize |= newSize >> 32; +#endif newSize++; newSize = MIN(newSize, ts->a_length >> 1);