Merge pull request #5570 from RaiKoHoff/Dev_Master

chore: upd uthash, add timsort (repl. qsort)
This commit is contained in:
Rainer Kottenhoff 2026-03-06 14:19:09 +01:00 committed by GitHub
commit 00fef58b1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 2868 additions and 159 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@
ehthumbs.db
Thumbs.db
.vscode
.venv
.agent
# C++ Junk #

View File

@ -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 <rettype> <Name>=<number>(<params>)
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())

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();
// ----------------------------------------------------------------------------

View File

@ -988,6 +988,8 @@
<ClCompile Include="StyleLexers\styleLexKiX.c" />
<ClCompile Include="StyleLexers\styleLexKotlin.c" />
<ClCompile Include="StyleLexers\styleLexVerilog.c" />
<ClCompile Include="timsort\timsort.c" />
<ClCompile Include="timsort\timsort_r.c" />
<ClCompile Include="tinyexpr\tinyexpr.c" />
<ClCompile Include="uchardet\uchardet\src\CharDistribution.cpp" />
<ClCompile Include="uchardet\uchardet\src\JpCntx.cpp" />
@ -1131,6 +1133,8 @@
<ClInclude Include="..\language\common_res.h" />
<ClInclude Include="DynStrg.h" />
<ClInclude Include="PathLib.h" />
<ClInclude Include="timsort\timsort-impl.h" />
<ClInclude Include="timsort\timsort.h" />
<ClInclude Include="tinyexpr\tinyexpr.h" />
<ClInclude Include="uchardet\uchardet\src\CharDistribution.h" />
<ClInclude Include="uchardet\uchardet\src\JpCntx.h" />

View File

@ -46,6 +46,9 @@
<Filter Include="Source Files\tinyexpr">
<UniqueIdentifier>{60486982-91be-42d2-b154-86c2706ca60f}</UniqueIdentifier>
</Filter>
<Filter Include="timsort">
<UniqueIdentifier>{9a2064fb-b044-4ce5-91de-99fa06cc5222}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Dialogs.c">
@ -432,6 +435,12 @@
<ClCompile Include="StyleLexers\styleLexVerilog.c">
<Filter>Source Files\StyleLexers</Filter>
</ClCompile>
<ClCompile Include="timsort\timsort.c">
<Filter>timsort</Filter>
</ClCompile>
<ClCompile Include="timsort\timsort_r.c">
<Filter>timsort</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Dlapi.h">
@ -611,6 +620,12 @@
<ClInclude Include="tinyexpr\tinyexpr.h">
<Filter>Source Files\tinyexpr</Filter>
</ClInclude>
<ClInclude Include="timsort\timsort.h">
<Filter>timsort</Filter>
</ClInclude>
<ClInclude Include="timsort\timsort-impl.h">
<Filter>timsort</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\res\Copy.cur">

View File

@ -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

View File

@ -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);
}

11
src/timsort/AUTHORS Normal file
View File

@ -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)

202
src/timsort/LICENSE Normal file
View File

@ -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.

156
src/timsort/README.md Normal file
View File

@ -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.

166
src/timsort/stresstest.c Normal file
View File

@ -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 <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

837
src/timsort/timsort-impl.h Normal file
View File

@ -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 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
*/
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; // " " " " "
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
/*
* Do the straightforward thing until (if ever) one run starts
* winning consistently.
*/
for (;;) {
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;
}
}; //~ do {...} 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 > 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; // " " " " "
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
/*
* 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;
}

423
src/timsort/timsort.c Normal file
View File

@ -0,0 +1,423 @@
/*
* 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.h> // assert
#include <errno.h> // EINVAL
#if defined(_MSC_VER)
# include <malloc.h> // _alloca
#endif
#include <stddef.h> // size_t, NULL
#include <stdlib.h> // malloc, free
#include <string.h> // 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;
#if (SIZE_MAX > 0xFFFFFFFFUL)
newSize |= newSize >> 32;
#endif
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));
}
}

65
src/timsort/timsort.h Normal file
View File

@ -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 */

18
src/timsort/timsort_r.c Normal file
View File

@ -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"

View File

@ -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.

View File

@ -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;

View File

@ -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 <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* 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 <stdint.h>, and must figure out their own way
to provide definitions for uint8_t and uint32_t. */
#else
#include <stdint.h> /* 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; \

View File

@ -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 { \

View File

@ -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

View File

@ -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

View File

@ -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 <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stringapiset.h>
#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 */