mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
Merge pull request #5570 from RaiKoHoff/Dev_Master
chore: upd uthash, add timsort (repl. qsort)
This commit is contained in:
commit
00fef58b1b
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
.vscode
|
||||
.venv
|
||||
.agent
|
||||
|
||||
# C++ Junk #
|
||||
|
||||
386
Build/scripts/check_scicall.py
Normal file
386
Build/scripts/check_scicall.py
Normal 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())
|
||||
18
src/Edit.c
18
src/Edit.c
@ -5533,23 +5533,23 @@ void EditSortLines(HWND hwnd, int iSortFlags)
|
||||
|
||||
if (iSortFlags & SORT_ASCENDING) {
|
||||
if (iSortFlags & SORT_NOCASE) {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdI);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdI);
|
||||
} else if (iSortFlags & SORT_LOGICAL) {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogical);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogical);
|
||||
} else if (iSortFlags & SORT_LEXICOGRAPH) {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographical);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographical);
|
||||
} else {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStd);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStd);
|
||||
}
|
||||
} else if (iSortFlags & SORT_DESCENDING) {
|
||||
if (iSortFlags & SORT_NOCASE) {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdIRev);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdIRev);
|
||||
} else if (iSortFlags & SORT_LOGICAL) {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogicalRev);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdLogicalRev);
|
||||
} else if (iSortFlags & SORT_LEXICOGRAPH) {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographicalRev);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpLexicographicalRev);
|
||||
} else {
|
||||
qsort(pLines, iLineCount, sizeof(SORTLINE), CmpStdRev);
|
||||
NP3_SORT(pLines, iLineCount, sizeof(SORTLINE), CmpStdRev);
|
||||
}
|
||||
} else { /*if (iSortFlags & SORT_SHUFFLE)*/
|
||||
srand((UINT)GetTicks_ms());
|
||||
@ -8372,7 +8372,7 @@ bool EditAutoCompleteWord(HWND hwnd, bool autoInsert)
|
||||
SciCall_AutoCSetChooseSingle(autoInsert);
|
||||
|
||||
const char* const sep = " ";
|
||||
SciCall_AutoCSetSeperator(sep[0]);
|
||||
SciCall_AutoCSetSeparator(sep[0]);
|
||||
|
||||
++iWListSize; // zero termination
|
||||
char* const pList = AllocMem(iWListSize + 1, HEAP_ZERO_MEMORY);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -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">
|
||||
|
||||
463
src/SciCall.h
463
src/SciCall.h
@ -163,8 +163,11 @@ DeclareSciCallR0(GetTechnology, GETTECHNOLOGY, int);
|
||||
DeclareSciCallV1(SetTechnology, SETTECHNOLOGY, int, technology);
|
||||
DeclareSciCallR0(GetBidirectional, GETBIDIRECTIONAL, int);
|
||||
DeclareSciCallV1(SetBidirectional, SETBIDIRECTIONAL, int, direction);
|
||||
DeclareSciCallR0(GetBufferedDraw, GETBUFFEREDDRAW, bool);
|
||||
DeclareSciCallV1(SetBufferedDraw, SETBUFFEREDDRAW, bool, value);
|
||||
DeclareSciCallR0(GetPhasesDraw, GETPHASESDRAW, int);
|
||||
DeclareSciCallV1(SetPhasesDraw, SETPHASESDRAW, int, phases);
|
||||
DeclareSciCallR0(GetCharacterCategoryOptimization, GETCHARACTERCATEGORYOPTIMIZATION, int);
|
||||
DeclareSciCallV1(SetCharacterCategoryOptimization, SETCHARACTERCATEGORYOPTIMIZATION, int, count);
|
||||
DeclareSciCallR1(SupportsFeature, SUPPORTSFEATURE, bool, int, feature);
|
||||
// Layout, Position Cache and Layout Threads
|
||||
@ -178,30 +181,49 @@ DeclareSciCallV1(SetLayoutThreads, SETLAYOUTTHREADS, int, threads);
|
||||
// Event Masks
|
||||
DeclareSciCallR0(GetModEventMask, GETMODEVENTMASK, int);
|
||||
DeclareSciCallV1(SetModEventMask, SETMODEVENTMASK, int, mask);
|
||||
DeclareSciCallR0(GetCommandEvents, GETCOMMANDEVENTS, bool);
|
||||
DeclareSciCallV1(SetCommandEvents, SETCOMMANDEVENTS, bool, flag);
|
||||
// Code Page
|
||||
DeclareSciCallR0(GetCodePage, GETCODEPAGE, int);
|
||||
DeclareSciCallV1(SetCodePage, SETCODEPAGE, int, cp);
|
||||
DeclareSciCallV1(StyleSetCharacterSet, STYLESETCHARACTERSET, int, cs);
|
||||
// Divers
|
||||
DeclareSciCallR0(GetMargins, GETMARGINS, int);
|
||||
DeclareSciCallV1(SetMargins, SETMARGINS, int, nmarg);
|
||||
DeclareSciCallV1(SetPasteConvertEndings, SETPASTECONVERTENDINGS, bool, flag);
|
||||
DeclareSciCallV1(UsePopUp, USEPOPUP, int, option);
|
||||
// Multi Selection
|
||||
DeclareSciCallR0(GetMultipleSelection, GETMULTIPLESELECTION, bool);
|
||||
DeclareSciCallV1(SetMultipleSelection, SETMULTIPLESELECTION, bool, flag);
|
||||
DeclareSciCallR0(GetMultiPaste, GETMULTIPASTE, int);
|
||||
DeclareSciCallV1(SetMultiPaste, SETMULTIPASTE, int, option);
|
||||
DeclareSciCallR0(GetAdditionalSelectionTyping, GETADDITIONALSELECTIONTYPING, bool);
|
||||
DeclareSciCallV1(SetAdditionalSelectionTyping, SETADDITIONALSELECTIONTYPING, bool, flag);
|
||||
DeclareSciCallR0(GetMouseSelectionRectangularSwitch, GETMOUSESELECTIONRECTANGULARSWITCH, bool);
|
||||
DeclareSciCallV1(SetMouseSelectionRectangularSwitch, SETMOUSESELECTIONRECTANGULARSWITCH, bool, flag);
|
||||
|
||||
// Caret Line
|
||||
DeclareSciCallR0(GetCaretLineVisible, GETCARETLINEVISIBLE, bool);
|
||||
DeclareSciCallV1(SetCaretLineVisible, SETCARETLINEVISIBLE, bool, show);
|
||||
DeclareSciCallR0(GetCaretLineBack, GETCARETLINEBACK, COLORREF);
|
||||
DeclareSciCallV1(SetCaretLineBack, SETCARETLINEBACK, COLORREF, back);
|
||||
DeclareSciCallR0(GetCaretLineBackAlpha, GETCARETLINEBACKALPHA, int);
|
||||
DeclareSciCallV1(SetCaretLineBackAlpha, SETCARETLINEBACKALPHA, int, alpha);
|
||||
DeclareSciCallR0(GetCaretLineLayer, GETCARETLINELAYER, int);
|
||||
DeclareSciCallV1(SetCaretLineLayer, SETCARETLINELAYER, int, layer);
|
||||
DeclareSciCallR0(GetCaretLineFrame, GETCARETLINEFRAME, int);
|
||||
DeclareSciCallV1(SetCaretLineFrame, SETCARETLINEFRAME, int, frm);
|
||||
DeclareSciCallR0(GetCaretLineVisibleAlways, GETCARETLINEVISIBLEALWAYS, bool);
|
||||
DeclareSciCallV1(SetCaretLineVisibleAlways, SETCARETLINEVISIBLEALWAYS, bool, flag);
|
||||
DeclareSciCallR0(GetCaretLineHighlightSubLine, GETCARETLINEHIGHLIGHTSUBLINE, bool);
|
||||
DeclareSciCallV1(SetCaretLineHighlightSubLine, SETCARETLINEHIGHLIGHTSUBLINE, bool, subLine);
|
||||
|
||||
DeclareSciCallR0(GetAutomaticFold, GETAUTOMATICFOLD, int);
|
||||
DeclareSciCallV1(SetAutomaticFold, SETAUTOMATICFOLD, int, option);
|
||||
|
||||
DeclareSciCallR0(GetCaretSticky, GETCARETSTICKY, int);
|
||||
DeclareSciCallV1(SetCaretSticky, SETCARETSTICKY, int, option);
|
||||
DeclareSciCallV0(ToggleCaretSticky, TOGGLECARETSTICKY);
|
||||
DeclareSciCallV2(SetXCaretPolicy, SETXCARETPOLICY, int, policy, int, slop);
|
||||
DeclareSciCallV2(SetYCaretPolicy, SETYCARETPOLICY, int, policy, int, slop);
|
||||
|
||||
@ -210,9 +232,38 @@ DeclareSciCallV01(GetWhiteSpaceChars, GETWHITESPACECHARS, char*, ptxt);
|
||||
DeclareSciCallV01(GetPunctuationChars, GETPUNCTUATIONCHARS, char*, ptxt);
|
||||
|
||||
DeclareSciCallV2(SetRepresentation, SETREPRESENTATION, const char*, encChar, const char*, represent);
|
||||
DeclareSciCallV2(SetRepresentationColour, SETREPRESENTATIONCOLOUR, const char*, encChar, COLORALPHAREF, colour);
|
||||
DeclareSciCallV2(SetRepresentationAppearance, SETREPRESENTATIONAPPEARANCE, const char*, encChar, int, appear);
|
||||
DeclareSciCallR2(GetRepresentation, GETREPRESENTATION, int, const char*, encodedCharacter, char*, representation);
|
||||
DeclareSciCallV1(ClearRepresentation, CLEARREPRESENTATION, const char*, encodedCharacter);
|
||||
DeclareSciCallV0(ClearAllRepresentations, CLEARALLREPRESENTATIONS);
|
||||
DeclareSciCallV2(SetRepresentationAppearance, SETREPRESENTATIONAPPEARANCE, const char*, encChar, int, appear);
|
||||
DeclareSciCallR1(GetRepresentationAppearance, GETREPRESENTATIONAPPEARANCE, int, const char*, encodedCharacter);
|
||||
DeclareSciCallV2(SetRepresentationColour, SETREPRESENTATIONCOLOUR, const char*, encChar, COLORALPHAREF, colour);
|
||||
DeclareSciCallR1(GetRepresentationColour, GETREPRESENTATIONCOLOUR, COLORALPHAREF, const char*, encodedCharacter);
|
||||
// Line End Types
|
||||
DeclareSciCallV1(SetLineEndTypesAllowed, SETLINEENDTYPESALLOWED, int, lineEndBitSet);
|
||||
DeclareSciCallR0(GetLineEndTypesAllowed, GETLINEENDTYPESALLOWED, int);
|
||||
DeclareSciCallR0(GetLineEndTypesActive, GETLINEENDTYPESACTIVE, int);
|
||||
// Tab Draw Mode
|
||||
DeclareSciCallR0(GetTabDrawMode, GETTABDRAWMODE, int);
|
||||
DeclareSciCallV1(SetTabDrawMode, SETTABDRAWMODE, int, tabDrawMode);
|
||||
// Tab Minimum Width
|
||||
DeclareSciCallV1(SetTabMinimumWidth, SETTABMINIMUMWIDTH, int, pixels);
|
||||
DeclareSciCallR0(GetTabMinimumWidth, GETTABMINIMUMWIDTH, int);
|
||||
// Accessibility
|
||||
DeclareSciCallV1(SetAccessibility, SETACCESSIBILITY, int, accessibility);
|
||||
DeclareSciCallR0(GetAccessibility, GETACCESSIBILITY, int);
|
||||
// Identifier
|
||||
DeclareSciCallV1(SetIdentifier, SETIDENTIFIER, int, identifier);
|
||||
DeclareSciCallR0(GetIdentifier, GETIDENTIFIER, int);
|
||||
// Font
|
||||
DeclareSciCallR0(GetFontQuality, GETFONTQUALITY, int);
|
||||
DeclareSciCallR01(GetFontLocale, GETFONTLOCALE, int, char*, localeName);
|
||||
// Direct Function Pointers
|
||||
DeclareSciCallR0(GetDirectFunction, GETDIRECTFUNCTION, sptr_t);
|
||||
DeclareSciCallR0(GetDirectStatusFunction, GETDIRECTSTATUSFUNCTION, sptr_t);
|
||||
// Allocation
|
||||
DeclareSciCallV1(AllocateLines, ALLOCATELINES, DocLn, lines);
|
||||
DeclareSciCallV1(Allocate, ALLOCATE, DocPos, bytes);
|
||||
|
||||
// Document Pointer Handling
|
||||
DeclareSciCallR0(GetDocPointer, GETDOCPOINTER, sptr_t);
|
||||
@ -242,9 +293,21 @@ DeclareSciCallV0(GrabFocus, GRABFOCUS);
|
||||
DeclareSciCallV1(SetFocus, SETFOCUS, bool, flag);
|
||||
DeclareSciCallR0(GetFocus, GETFOCUS, bool);
|
||||
DeclareSciCallR0(GetPasteConvertEndings, GETPASTECONVERTENDINGS, bool);
|
||||
DeclareSciCallV1(SetOvertype, SETOVERTYPE, bool, overType);
|
||||
DeclareSciCallR0(GetOverType, GETOVERTYPE, bool);
|
||||
DeclareSciCallR0(GetReadOnly, GETREADONLY, bool);
|
||||
DeclareSciCallV1(SetReadOnly, SETREADONLY, bool, flag);
|
||||
DeclareSciCallR0(GetSelectionHidden, GETSELECTIONHIDDEN, bool);
|
||||
DeclareSciCallV1(HideSelection, HIDESELECTION, bool, hide);
|
||||
DeclareSciCallV1(SetStatus, SETSTATUS, int, status);
|
||||
DeclareSciCallR0(GetStatus, GETSTATUS, int);
|
||||
DeclareSciCallV1(SetMouseDownCaptures, SETMOUSEDOWNCAPTURES, bool, captures);
|
||||
DeclareSciCallR0(GetMouseDownCaptures, GETMOUSEDOWNCAPTURES, bool);
|
||||
DeclareSciCallV1(SetMouseWheelCaptures, SETMOUSEWHEELCAPTURES, bool, captures);
|
||||
DeclareSciCallR0(GetMouseWheelCaptures, GETMOUSEWHEELCAPTURES, bool);
|
||||
DeclareSciCallR0(GetCursor, GETCURSOR, int);
|
||||
DeclareSciCallV1(SetControlCharSymbol, SETCONTROLCHARSYMBOL, int, symbol);
|
||||
DeclareSciCallR0(GetControlCharSymbol, GETCONTROLCHARSYMBOL, int);
|
||||
|
||||
DeclareSciCallV1(SetSelectionLayer, SETSELECTIONLAYER, int, layer);
|
||||
DeclareSciCallR0(GetSelectionLayer, GETSELECTIONLAYER, int);
|
||||
@ -267,8 +330,30 @@ DeclareSciCallR01(PointYFromPosition, POINTYFROMPOSITION, int, DocPos, position)
|
||||
DeclareSciCallR2(WordStartPosition, WORDSTARTPOSITION, DocPos, DocPos, pos, bool, onlyWordChars);
|
||||
DeclareSciCallR2(WordEndPosition, WORDENDPOSITION, DocPos, DocPos, pos, bool, onlyWordChars);
|
||||
|
||||
// Selection colors
|
||||
DeclareSciCallV2(SetSelFore, SETSELFORE, bool, useSetting, COLORREF, fore);
|
||||
DeclareSciCallV2(SetSelBack, SETSELBACK, bool, useSetting, COLORREF, back);
|
||||
DeclareSciCallR0(GetSelAlpha, GETSELALPHA, int);
|
||||
DeclareSciCallV1(SetSelAlpha, SETSELALPHA, int, alpha);
|
||||
DeclareSciCallR0(GetSelEOLFilled, GETSELEOLFILLED, bool);
|
||||
DeclareSciCallV1(SetAdditionalSelFore, SETADDITIONALSELFORE, COLORREF, fore);
|
||||
DeclareSciCallV1(SetAdditionalSelBack, SETADDITIONALSELBACK, COLORREF, back);
|
||||
DeclareSciCallV1(SetAdditionalSelAlpha, SETADDITIONALSELALPHA, int, alpha);
|
||||
DeclareSciCallR0(GetAdditionalSelAlpha, GETADDITIONALSELALPHA, int);
|
||||
DeclareSciCallV1(SetAdditionalCaretFore, SETADDITIONALCARETFORE, COLORREF, fore);
|
||||
DeclareSciCallR0(GetAdditionalCaretFore, GETADDITIONALCARETFORE, COLORREF);
|
||||
DeclareSciCallR0(GetAdditionalCaretsBlink, GETADDITIONALCARETSBLINK, bool);
|
||||
DeclareSciCallR0(GetAdditionalCaretsVisible, GETADDITIONALCARETSVISIBLE, bool);
|
||||
DeclareSciCallV2(SetWhitespaceFore, SETWHITESPACEFORE, bool, useSetting, COLORREF, fore);
|
||||
DeclareSciCallV2(SetWhitespaceBack, SETWHITESPACEBACK, bool, useSetting, COLORREF, back);
|
||||
DeclareSciCallV1(SetCaretFore, SETCARETFORE, COLORREF, fore);
|
||||
DeclareSciCallR0(GetCaretFore, GETCARETFORE, COLORREF);
|
||||
|
||||
// Rectangular selection with virtual space
|
||||
DeclareSciCallR0(GetVirtualSpaceOptions, GETVIRTUALSPACEOPTIONS, int);
|
||||
DeclareSciCallV1(SetVirtualSpaceOptions, SETVIRTUALSPACEOPTIONS, int, options);
|
||||
DeclareSciCallV1(SetRectangularSelectionModifier, SETRECTANGULARSELECTIONMODIFIER, int, modifier);
|
||||
DeclareSciCallR0(GetRectangularSelectionModifier, GETRECTANGULARSELECTIONMODIFIER, int);
|
||||
DeclareSciCallR0(GetRectangularSelectionCaret, GETRECTANGULARSELECTIONCARET, DocPos);
|
||||
DeclareSciCallV1(SetRectangularSelectionCaret, SETRECTANGULARSELECTIONCARET, DocPos, position);
|
||||
DeclareSciCallR0(GetRectangularSelectionAnchor, GETRECTANGULARSELECTIONANCHOR, DocPos);
|
||||
@ -284,7 +369,6 @@ DeclareSciCallR0(GetSelectionMode, GETSELECTIONMODE, int);
|
||||
DeclareSciCallV1(SetSelectionMode, SETSELECTIONMODE, int, mode);
|
||||
DeclareSciCallV1(ChangeSelectionMode, CHANGESELECTIONMODE, int, mode);
|
||||
DeclareSciCallR0(GetSelections, GETSELECTIONS, DocPosU);
|
||||
DeclareSciCallR0(GetSelectionEmpty, GETSELECTIONS, bool);
|
||||
DeclareSciCallV2(SetSelection, SETSELECTION, DocPos, caretPos, DocPos, anchorPos);
|
||||
DeclareSciCallV1(SetSelectionStart, SETSELECTIONSTART, DocPos, anchorPos);
|
||||
DeclareSciCallV1(SetSelectionEnd, SETSELECTIONEND, DocPos, caretPos);
|
||||
@ -302,10 +386,19 @@ DeclareSciCallV2(SetSelectionNAnchorVirtualSpace, SETSELECTIONNANCHORVIRTUALSPAC
|
||||
DeclareSciCallR1(GetSelectionNStart, GETSELECTIONNSTART, DocPos, DocPosU, selnum);
|
||||
DeclareSciCallR1(GetSelectionNEnd, GETSELECTIONNEND, DocPos, DocPosU, selnum);
|
||||
DeclareSciCallR1(GetSelectionNStartVirtualSpace, GETSELECTIONNSTARTVIRTUALSPACE, DocPos, DocPosU, selnum);
|
||||
DeclareSciCallV2(SetSelectionNStart, SETSELECTIONNSTART, int, selection, DocPos, anchor);
|
||||
DeclareSciCallV2(SetSelectionNEnd, SETSELECTIONNEND, int, selection, DocPos, caret);
|
||||
DeclareSciCallR1(GetSelectionNEndVirtualSpace, GETSELECTIONNENDVIRTUALSPACE, DocPos, DocPosU, selnum);
|
||||
DeclareSciCallV1(DropSelectionN, DROPSELECTIONN, int, selection);
|
||||
DeclareSciCallV1(SetMoveExtendsSelection, SETMOVEEXTENDSSELECTION, bool, moveExtendsSelection);
|
||||
DeclareSciCallR0(GetMoveExtendsSelection, GETMOVEEXTENDSSELECTION, bool);
|
||||
DeclareSciCallR2(SelectionFromPoint, SELECTIONFROMPOINT, int, int, x, int, y);
|
||||
// Serialized selection
|
||||
DeclareSciCallV01(SetSelectionSerialized, SETSELECTIONSERIALIZED, const char*, selectionString);
|
||||
DeclareSciCallR01(GetSelectionSerialized, GETSELECTIONSERIALIZED, DocPos, char*, selectionString);
|
||||
|
||||
DeclareSciCallV0(SwapMainAnchorCaret, SWAPMAINANCHORCARET);
|
||||
DeclareSciCallV0(MultipleSelectAddNext, MULTIPLESELECTADDNEXT);
|
||||
DeclareSciCallV0(MultipleSelectAddEach, MULTIPLESELECTADDEACH);
|
||||
DeclareSciCallV0(RotateSelection, ROTATESELECTION);
|
||||
|
||||
@ -320,40 +413,96 @@ DeclareSciCallV0(ZoomOut, ZOOMOUT);
|
||||
// while the SCI_VCHOME* commands move the caret to the first non-blank character of the line
|
||||
// (ie. just after the indentation) unless it is already there; in this case, it acts as SCI_HOME*.
|
||||
DeclareSciCallV0(Home, HOME);
|
||||
DeclareSciCallV0(HomeExtend, HOMEEXTEND);
|
||||
DeclareSciCallV0(VCHome, VCHOME);
|
||||
DeclareSciCallV0(VCHomeExtend, VCHOMEEXTEND);
|
||||
DeclareSciCallV0(VCHomeWrap, VCHOMEWRAP);
|
||||
DeclareSciCallV0(VCHomeWrapExtend, VCHOMEWRAPEXTEND);
|
||||
DeclareSciCallV0(VCHomeDisplay, VCHOMEDISPLAY);
|
||||
DeclareSciCallV0(VCHomeDisplayExtend, VCHOMEDISPLAYEXTEND);
|
||||
DeclareSciCallV0(LineEnd, LINEEND);
|
||||
DeclareSciCallV0(LineEndExtend, LINEENDEXTEND);
|
||||
DeclareSciCallV0(LineEndWrap, LINEENDWRAP);
|
||||
DeclareSciCallV0(LineEndWrapExtend, LINEENDWRAPEXTEND);
|
||||
DeclareSciCallV0(LineEndDisplay, LINEENDDISPLAY);
|
||||
DeclareSciCallV0(LineEndDisplayExtend, LINEENDDISPLAYEXTEND);
|
||||
DeclareSciCallV0(HomeDisplay, HOMEDISPLAY);
|
||||
DeclareSciCallV0(HomeDisplayExtend, HOMEDISPLAYEXTEND);
|
||||
DeclareSciCallV0(HomeWrap, HOMEWRAP);
|
||||
DeclareSciCallV0(HomeWrapExtend, HOMEWRAPEXTEND);
|
||||
DeclareSciCallV0(NewLine, NEWLINE);
|
||||
DeclareSciCallV0(FormFeed, FORMFEED);
|
||||
DeclareSciCallV0(Tab, TAB);
|
||||
DeclareSciCallV0(BackTab, BACKTAB);
|
||||
DeclareSciCallV0(LineIndent, LINEINDENT);
|
||||
DeclareSciCallV0(LineDedent, LINEDEDENT);
|
||||
DeclareSciCallV0(LineUp, LINEUP);
|
||||
DeclareSciCallV0(LineDown, LINEDOWN);
|
||||
DeclareSciCallV0(LineUpExtend, LINEUPEXTEND);
|
||||
DeclareSciCallV0(LineScrollUp, LINESCROLLUP);
|
||||
DeclareSciCallV0(LineDown, LINEDOWN);
|
||||
DeclareSciCallV0(LineDownExtend, LINEDOWNEXTEND);
|
||||
DeclareSciCallV0(LineScrollUp, LINESCROLLUP);
|
||||
DeclareSciCallV0(LineScrollDown, LINESCROLLDOWN);
|
||||
DeclareSciCallV0(CharLeft, CHARLEFT);
|
||||
DeclareSciCallV0(CharLeftExtend, CHARLEFTEXTEND);
|
||||
DeclareSciCallV0(CharRight, CHARRIGHT);
|
||||
DeclareSciCallV0(CharRightExtend, CHARRIGHTEXTEND);
|
||||
DeclareSciCallV0(WordLeft, WORDLEFT);
|
||||
DeclareSciCallV0(WordLeftExtend, WORDLEFTEXTEND);
|
||||
DeclareSciCallV0(WordRight, WORDRIGHT);
|
||||
DeclareSciCallV0(WordRightExtend, WORDRIGHTEXTEND);
|
||||
DeclareSciCallV0(WordPartLeft, WORDPARTLEFT);
|
||||
DeclareSciCallV0(WordPartLeftExtend, WORDPARTLEFTEXTEND);
|
||||
DeclareSciCallV0(WordPartRight, WORDPARTRIGHT);
|
||||
DeclareSciCallV0(WordPartRightExtend, WORDPARTRIGHTEXTEND);
|
||||
DeclareSciCallV0(WordLeftEnd, WORDLEFTEND);
|
||||
DeclareSciCallV0(WordLeftEndExtend, WORDLEFTENDEXTEND);
|
||||
DeclareSciCallV0(WordRightEnd, WORDRIGHTEND);
|
||||
DeclareSciCallV0(WordRightEndExtend, WORDRIGHTENDEXTEND);
|
||||
DeclareSciCallV0(DocumentStart, DOCUMENTSTART);
|
||||
DeclareSciCallV0(DocumentStartExtend, DOCUMENTSTARTEXTEND);
|
||||
DeclareSciCallV0(DocumentEnd, DOCUMENTEND);
|
||||
DeclareSciCallV0(DocumentEndExtend, DOCUMENTENDEXTEND);
|
||||
DeclareSciCallV0(PageUp, PAGEUP);
|
||||
DeclareSciCallV0(PageUpExtend, PAGEUPEXTEND);
|
||||
DeclareSciCallV0(PageDown, PAGEDOWN);
|
||||
DeclareSciCallV0(PageDownExtend, PAGEDOWNEXTEND);
|
||||
DeclareSciCallV0(StutteredPageUp, STUTTEREDPAGEUP);
|
||||
DeclareSciCallV0(StutteredPageUpExtend, STUTTEREDPAGEUPEXTEND);
|
||||
DeclareSciCallV0(StutteredPageDown, STUTTEREDPAGEDOWN);
|
||||
DeclareSciCallV0(StutteredPageDownExtend, STUTTEREDPAGEDOWNEXTEND);
|
||||
DeclareSciCallV0(ParaUp, PARAUP);
|
||||
DeclareSciCallV0(ParaUpExtend, PARAUPEXTEND);
|
||||
DeclareSciCallV0(ParaDown, PARADOWN);
|
||||
DeclareSciCallV0(ParaDownExtend, PARADOWNEXTEND);
|
||||
// Rectangular extension
|
||||
DeclareSciCallV0(LineDownRectExtend, LINEDOWNRECTEXTEND);
|
||||
DeclareSciCallV0(LineUpRectExtend, LINEUPRECTEXTEND);
|
||||
DeclareSciCallV0(CharLeftRectExtend, CHARLEFTRECTEXTEND);
|
||||
DeclareSciCallV0(CharRightRectExtend, CHARRIGHTRECTEXTEND);
|
||||
DeclareSciCallV0(HomeRectExtend, HOMERECTEXTEND);
|
||||
DeclareSciCallV0(VCHomeRectExtend, VCHOMERECTEXTEND);
|
||||
DeclareSciCallV0(LineEndRectExtend, LINEENDRECTEXTEND);
|
||||
DeclareSciCallV0(PageUpRectExtend, PAGEUPRECTEXTEND);
|
||||
DeclareSciCallV0(PageDownRectExtend, PAGEDOWNRECTEXTEND);
|
||||
// Delete and line operations
|
||||
DeclareSciCallV0(DeleteBack, DELETEBACK);
|
||||
DeclareSciCallV0(DeleteBackNotLine, DELETEBACKNOTLINE);
|
||||
DeclareSciCallV0(DelWordLeft, DELWORDLEFT);
|
||||
DeclareSciCallV0(DelWordRight, DELWORDRIGHT);
|
||||
DeclareSciCallV0(DelWordRightEnd, DELWORDRIGHTEND);
|
||||
DeclareSciCallV0(DelLineLeft, DELLINELEFT);
|
||||
DeclareSciCallV0(DelLineRight, DELLINERIGHT);
|
||||
DeclareSciCallV0(LineDelete, LINEDELETE);
|
||||
DeclareSciCallV0(LineCut, LINECUT);
|
||||
DeclareSciCallV0(LineCopy, LINECOPY);
|
||||
DeclareSciCallV0(LineReverse, LINEREVERSE);
|
||||
DeclareSciCallV1(LinesSplit, LINESSPLIT, int, pix);
|
||||
DeclareSciCallV0(LinesJoin, LINESJOIN);
|
||||
DeclareSciCallV0(EditToggleOverType, EDITTOGGLEOVERTYPE);
|
||||
|
||||
DeclareSciCallV2(AssignCmdKey, ASSIGNCMDKEY, size_t, key, unsigned, cmd);
|
||||
DeclareSciCallV1(ClearCmdKey, CLEARCMDKEY, size_t, keyDefinition);
|
||||
DeclareSciCallV0(ClearAllCmdKeys, CLEARALLCMDKEYS);
|
||||
|
||||
// Commands
|
||||
DeclareSciCallV0(LineDuplicate, LINEDUPLICATE);
|
||||
@ -361,7 +510,12 @@ DeclareSciCallV0(SelectionDuplicate, SELECTIONDUPLICATE);
|
||||
DeclareSciCallV0(LineTranspose, LINETRANSPOSE);
|
||||
DeclareSciCallV0(MoveSelectedLinesUp, MOVESELECTEDLINESUP);
|
||||
DeclareSciCallV0(MoveSelectedLinesDown, MOVESELECTEDLINESDOWN);
|
||||
DeclareSciCallV0(CutAllowLine, CUTALLOWLINE);
|
||||
DeclareSciCallR2(FindText, FINDTEXT, DocPos, int, searchFlags, struct Sci_TextToFind*, ft);
|
||||
DeclareSciCallR2(FindTextFull, FINDTEXTFULL, DocPos, int, flags, struct Sci_TextToFindFull*, text);
|
||||
DeclareSciCallV0(SearchAnchor, SEARCHANCHOR);
|
||||
DeclareSciCallR2(SearchNext, SEARCHNEXT, DocPos, int, searchFlags, const char*, text);
|
||||
DeclareSciCallR2(SearchPrev, SEARCHPREV, DocPos, int, searchFlags, const char*, text);
|
||||
|
||||
// Operations
|
||||
DeclareSciCallV0(Cut, CUT);
|
||||
@ -373,13 +527,45 @@ DeclareSciCallV2(CopyRange, COPYRANGE, DocPos, start, DocPos, end);
|
||||
DeclareSciCallV0(Cancel, CANCEL);
|
||||
DeclareSciCallV0(CopyAllowLine, COPYALLOWLINE);
|
||||
DeclareSciCallV2(CopyText, COPYTEXT, DocPos, length, const char*, text);
|
||||
DeclareSciCallV2(AddStyledText, ADDSTYLEDTEXT, DocPos, length, const char*, c);
|
||||
DeclareSciCallR0(GetLength, GETLENGTH, DocPos);
|
||||
DeclareSciCallR1(GetStyleAt, GETSTYLEAT, int, DocPos, pos);
|
||||
DeclareSciCallR01(GetStyledText, GETSTYLEDTEXT, DocPos, struct Sci_TextRange*, tr);
|
||||
DeclareSciCallR01(GetStyledTextFull, GETSTYLEDTEXTFULL, DocPos, struct Sci_TextRangeFull*, tr);
|
||||
DeclareSciCallR01(GetTextRange, GETTEXTRANGE, DocPos, struct Sci_TextRange*, tr);
|
||||
DeclareSciCallR2(GetText, GETTEXT, DocPos, DocPos, length, const char*, text); // NULL: w/o terminating '\0' (SCI v515)
|
||||
DeclareSciCallR01(GetTextRangeFull, GETTEXTRANGEFULL, DocPos, struct Sci_TextRangeFull*, textrange);
|
||||
DeclareSciCallV01(SetText, SETTEXT, const char*, text);
|
||||
DeclareSciCallV0(Null, NULL);
|
||||
DeclareSciCallV0(UpperCase, UPPERCASE);
|
||||
DeclareSciCallV0(LowerCase, LOWERCASE);
|
||||
DeclareSciCallV2(ReplaceRectangular, REPLACERECTANGULAR, DocPos, length, const char *, text);
|
||||
DeclareSciCallV01(SetCopySeparator, SETCOPYSEPARATOR, const char*, sep);
|
||||
|
||||
DeclareSciCallR01(GetCopySeparator, GETCOPYSEPARATOR, int, char*, separator);
|
||||
DeclareSciCallV2(SetStylingEx, SETSTYLINGEX, DocPos, length, const char*, styles);
|
||||
DeclareSciCallR0(GetSearchFlags, GETSEARCHFLAGS, int);
|
||||
DeclareSciCallV1(SetTargetStart, SETTARGETSTART, DocPos, start);
|
||||
DeclareSciCallV1(SetTargetEnd, SETTARGETEND, DocPos, end);
|
||||
DeclareSciCallV1(SetTargetStartVirtualSpace, SETTARGETSTARTVIRTUALSPACE, DocPos, space);
|
||||
DeclareSciCallR0(GetTargetStartVirtualSpace, GETTARGETSTARTVIRTUALSPACE, DocPos);
|
||||
DeclareSciCallV1(SetTargetEndVirtualSpace, SETTARGETENDVIRTUALSPACE, DocPos, space);
|
||||
DeclareSciCallR0(GetTargetEndVirtualSpace, GETTARGETENDVIRTUALSPACE, DocPos);
|
||||
DeclareSciCallR2(IsRangeWord, ISRANGEWORD, bool, DocPos, start, DocPos, end);
|
||||
DeclareSciCallR2(CountCodeUnits, COUNTCODEUNITS, DocPos, DocPos, start, DocPos, end);
|
||||
DeclareSciCallR2(PositionRelativeCodeUnits, POSITIONRELATIVECODEUNITS, DocPos, DocPos, pos, DocPos, relative);
|
||||
DeclareSciCallR1(TextHeight, TEXTHEIGHT, int, DocLn, line);
|
||||
DeclareSciCallR2(GetTag, GETTAG, int, int, tagNumber, char*, tagValue);
|
||||
DeclareSciCallR2(ChangeLexerState, CHANGELEXERSTATE, int, DocPos, start, DocPos, end);
|
||||
DeclareSciCallR0(GetGapPosition, GETGAPPOSITION, DocPos);
|
||||
// Line Character Index
|
||||
DeclareSciCallR0(GetLineCharacterIndex, GETLINECHARACTERINDEX, int);
|
||||
DeclareSciCallV1(AllocateLineCharacterIndex, ALLOCATELINECHARACTERINDEX, int, lineCharacterIndex);
|
||||
DeclareSciCallV1(ReleaseLineCharacterIndex, RELEASELINECHARACTERINDEX, int, lineCharacterIndex);
|
||||
DeclareSciCallR2(LineFromIndexPosition, LINEFROMINDEXPOSITION, DocLn, DocPos, pos, int, lineCharacterIndex);
|
||||
DeclareSciCallR2(IndexPositionFromLine, INDEXPOSITIONFROMLINE, DocPos, DocLn, line, int, lineCharacterIndex);
|
||||
// Encoding
|
||||
DeclareSciCallV1(SetLengthForEncode, SETLENGTHFORENCODE, DocPos, bytes);
|
||||
DeclareSciCallR2(EncodedFromUTF8, ENCODEDFROMUTF8, DocPos, const char*, utf8, char*, encoded);
|
||||
|
||||
//DeclareSciCallR01(TargetAsUTF8, TARGETASUTF8, DocPos, const char*, text); // WideCharToMultiByteEx(Encoding_SciCP);
|
||||
// SCI_ENCODEDFROMUTF8 - no need, internal CP is UTF8 always (fixed const for Notepad3);
|
||||
@ -413,8 +599,6 @@ DeclareSciCallV1(SetCurrentPos, SETCURRENTPOS, DocPos, position);
|
||||
|
||||
DeclareSciCallV1(GotoPos, GOTOPOS, DocPos, position);
|
||||
DeclareSciCallV1(GotoLine, GOTOLINE, DocLn, line);
|
||||
DeclareSciCallV0(DocumentStart, DOCUMENTSTART);
|
||||
DeclareSciCallV0(DocumentEnd, DOCUMENTEND);
|
||||
DeclareSciCallR1(PositionBefore, POSITIONBEFORE, DocPos, DocPos, position);
|
||||
DeclareSciCallR1(PositionAfter, POSITIONAFTER, DocPos, DocPos, position);
|
||||
DeclareSciCallR1(GetCharAt, GETCHARAT, char, DocPos, position);
|
||||
@ -476,27 +660,62 @@ DeclareSciCallV1(CallTipSetForeHlt, CALLTIPSETFOREHLT, COLORREF, colour);
|
||||
DeclareSciCallV1(CallTipSetBack, CALLTIPSETBACK, COLORREF, colour);
|
||||
DeclareSciCallV1(CallTipSetPosition, CALLTIPSETPOSITION, bool, above);
|
||||
DeclareSciCallR0(CallTipPosStart, CALLTIPPOSSTART, DocPos);
|
||||
DeclareSciCallV1(CallTipSetPosStart, CALLTIPSETPOSSTART, DocPos, posStart);
|
||||
DeclareSciCallV2(CallTipShow, CALLTIPSHOW, DocPos, position, const char*, text);
|
||||
DeclareSciCallV2(CallTipSetHlt, CALLTIPSETHLT, int, beg, int, end);
|
||||
DeclareSciCallR0(CallTipActive, CALLTIPACTIVE, bool);
|
||||
DeclareSciCallV0(CallTipCancel, CALLTIPCANCEL);
|
||||
DeclareSciCallV1(CallTipUseStyle, CALLTIPUSESTYLE, int, tabsize);
|
||||
DeclareSciCallV1(SetMouseDWellTime, SETMOUSEDWELLTIME, int, millisec);
|
||||
DeclareSciCallR0(GetMouseDwellTime, GETMOUSEDWELLTIME, int);
|
||||
|
||||
DeclareSciCallR0(AutoCActive, AUTOCACTIVE, bool);
|
||||
DeclareSciCallV0(AutoCComplete, AUTOCCOMPLETE);
|
||||
DeclareSciCallV0(AutoCCancel, AUTOCCANCEL);
|
||||
DeclareSciCallV0(ClearRegisteredImages, CLEARREGISTEREDIMAGES);
|
||||
DeclareSciCallV1(AutoCSetOptions, AUTOCSETOPTIONS, int, options);
|
||||
DeclareSciCallV1(AutoCSetIgnoreCase, AUTOCSETIGNORECASE, bool, flag);
|
||||
DeclareSciCallV1(AutoCSetCaseInsensitiveBehaviour, AUTOCSETCASEINSENSITIVEBEHAVIOUR, int, options);
|
||||
DeclareSciCallV1(AutoCSetSeperator, AUTOCSETSEPARATOR, char, seperator);
|
||||
DeclareSciCallR0(AutoCPosStart, AUTOCPOSSTART, DocPos);
|
||||
DeclareSciCallV01(AutoCStops, AUTOCSTOPS, const char*, characterSet);
|
||||
DeclareSciCallV1(AutoCSetSeparator, AUTOCSETSEPARATOR, char, separator);
|
||||
DeclareSciCallR0(AutoCGetSeparator, AUTOCGETSEPARATOR, int);
|
||||
DeclareSciCallV01(AutoCSelect, AUTOCSELECT, const char*, select);
|
||||
DeclareSciCallV1(AutoCSetStyle, AUTOCSETSTYLE, int, style);
|
||||
DeclareSciCallR0(AutoCGetStyle, AUTOCGETSTYLE, int);
|
||||
DeclareSciCallV1(AutoCSetCancelAtStart, AUTOCSETCANCELATSTART, bool, cancel);
|
||||
DeclareSciCallR0(AutoCGetCancelAtStart, AUTOCGETCANCELATSTART, bool);
|
||||
DeclareSciCallV01(AutoCSetFillups, AUTOCSETFILLUPS, const char*, text);
|
||||
DeclareSciCallV1(AutoCSetChooseSingle, AUTOCSETCHOOSESINGLE, bool, flag);
|
||||
DeclareSciCallR0(AutoCGetChooseSingle, AUTOCGETCHOOSESINGLE, bool);
|
||||
DeclareSciCallV1(AutoCSetIgnoreCase, AUTOCSETIGNORECASE, bool, flag);
|
||||
DeclareSciCallR0(AutoCGetIgnoreCase, AUTOCGETIGNORECASE, bool);
|
||||
DeclareSciCallV1(AutoCSetAutoHide, AUTOCSETAUTOHIDE, bool, autoHide);
|
||||
DeclareSciCallR0(AutoCGetAutoHide, AUTOCGETAUTOHIDE, bool);
|
||||
DeclareSciCallV1(AutoCSetDropRestOfWord, AUTOCSETDROPRESTOFWORD, bool, dropRestOfWord);
|
||||
DeclareSciCallR0(AutoCGetDropRestOfWord, AUTOCGETDROPRESTOFWORD, bool);
|
||||
DeclareSciCallV1(AutoCSetTypeSeparator, AUTOCSETTYPESEPARATOR, int, separatorCharacter);
|
||||
DeclareSciCallR0(AutoCGetTypeSeparator, AUTOCGETTYPESEPARATOR, int);
|
||||
DeclareSciCallV1(AutoCSetMaxWidth, AUTOCSETMAXWIDTH, int, characterCount);
|
||||
DeclareSciCallR0(AutoCGetMaxWidth, AUTOCGETMAXWIDTH, int);
|
||||
DeclareSciCallV1(AutoCSetMaxHeight, AUTOCSETMAXHEIGHT, int, rowCount);
|
||||
DeclareSciCallR0(AutoCGetMaxHeight, AUTOCGETMAXHEIGHT, int);
|
||||
DeclareSciCallV1(AutoCSetOptions, AUTOCSETOPTIONS, int, options);
|
||||
DeclareSciCallR0(AutoCGetOptions, AUTOCGETOPTIONS, int);
|
||||
DeclareSciCallV1(AutoCSetCaseInsensitiveBehaviour, AUTOCSETCASEINSENSITIVEBEHAVIOUR, int, options);
|
||||
DeclareSciCallR0(AutoCGetCaseInsensitiveBehaviour, AUTOCGETCASEINSENSITIVEBEHAVIOUR, int);
|
||||
DeclareSciCallR0(AutoCGetOrder, AUTOCGETORDER, int);
|
||||
DeclareSciCallV1(AutoCSetOrder, AUTOCSETORDER, int, options);
|
||||
DeclareSciCallV1(AutoCSetMulti, AUTOCSETMULTI, int, options);
|
||||
DeclareSciCallR0(AutoCGetMulti, AUTOCGETMULTI, int);
|
||||
DeclareSciCallR0(AutoCGetCurrent, AUTOCGETCURRENT, int);
|
||||
DeclareSciCallR01(AutoCGetCurrentText, AUTOCGETCURRENTTEXT, int, char*, text);
|
||||
DeclareSciCallV1(AutoCSetImageScale, AUTOCSETIMAGESCALE, int, scalePercent);
|
||||
DeclareSciCallR0(AutoCGetImageScale, AUTOCGETIMAGESCALE, int);
|
||||
DeclareSciCallV2(AutoCShow, AUTOCSHOW, DocPos, len, const char*, list);
|
||||
DeclareSciCallV2(UserListShow, USERLISTSHOW, int, listType, const char*, itemList);
|
||||
DeclareSciCallV2(RegisterImage, REGISTERIMAGE, int, type, const char*, xpmData);
|
||||
DeclareSciCallV2(RegisterRGBAImage, REGISTERRGBAIMAGE, int, type, const char*, pixels);
|
||||
DeclareSciCallV1(RGBAImageSetWidth, RGBAIMAGESETWIDTH, int, width);
|
||||
DeclareSciCallV1(RGBAImageSetHeight, RGBAIMAGESETHEIGHT, int, height);
|
||||
DeclareSciCallV1(RGBAImageSetScale, RGBAIMAGESETSCALE, int, scalePercent);
|
||||
DeclareSciCallV0(ClearRegisteredImages, CLEARREGISTEREDIMAGES);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
@ -509,16 +728,22 @@ DeclareSciCallV0(ScrollCaret, SCROLLCARET);
|
||||
DeclareSciCallV0(ChooseCaretX, CHOOSECARETX);
|
||||
DeclareSciCallV2(LineScroll, LINESCROLL, DocPos, columns, DocLn, lines);
|
||||
DeclareSciCallV2(ScrollRange, SCROLLRANGE, DocPos, secondaryPos, DocPos, primaryPos);
|
||||
DeclareSciCallR0(GetScrollWidth, GETSCROLLWIDTH, int);
|
||||
DeclareSciCallV1(SetScrollWidth, SETSCROLLWIDTH, int, width);
|
||||
DeclareSciCallR0(GetScrollWidthTracking, GETSCROLLWIDTHTRACKING, bool);
|
||||
DeclareSciCallV1(SetScrollWidthTracking, SETSCROLLWIDTHTRACKING, bool, srwt);
|
||||
|
||||
DeclareSciCallR0(GetEndAtLastLine, GETENDATLASTLINE, bool);
|
||||
DeclareSciCallV1(SetEndAtLastLine, SETENDATLASTLINE, bool, flag);
|
||||
DeclareSciCallR0(GetXOffset, GETXOFFSET, int);
|
||||
DeclareSciCallV1(SetXOffset, SETXOFFSET, int, offset);
|
||||
DeclareSciCallV2(SetVisiblePolicy, SETVISIBLEPOLICY, int, flags, DocLn, lines);
|
||||
DeclareSciCallV0(MoveCaretInsideView, MOVECARETINSIDEVIEW);
|
||||
|
||||
DeclareSciCallV0(VerticalCentreCaret, VERTICALCENTRECARET);
|
||||
DeclareSciCallV2(ShowLines, SHOWLINES, DocLn, lnStart, DocLn, lnEnd);
|
||||
DeclareSciCallV2(HideLines, HIDELINES, DocLn, lineStart, DocLn, lineEnd);
|
||||
DeclareSciCallR0(GetAllLinesVisible, GETALLLINESVISIBLE, bool);
|
||||
DeclareSciCallR0(LinesOnScreen, LINESONSCREEN, DocLn);
|
||||
DeclareSciCallR1(GetLineVisible, GETLINEVISIBLE, bool, DocLn, line);
|
||||
DeclareSciCallR0(GetFirstVisibleLine, GETFIRSTVISIBLELINE, DocLn);
|
||||
@ -527,7 +752,9 @@ DeclareSciCallV2(ScrollVertical, SCROLLVERTICAL, DocLn, docLine, DocLn, subLine)
|
||||
DeclareSciCallR1(VisibleFromDocLine, VISIBLEFROMDOCLINE, DocLn, DocLn, line);
|
||||
DeclareSciCallR1(DocLineFromVisible, DOCLINEFROMVISIBLE, DocLn, DocLn, line);
|
||||
|
||||
DeclareSciCallR0(GetHScrollBar, GETHSCROLLBAR, bool);
|
||||
DeclareSciCallV1(SetHScrollbar, SETHSCROLLBAR, bool, visible);
|
||||
DeclareSciCallR0(GetVScrollBar, GETVSCROLLBAR, bool);
|
||||
DeclareSciCallV1(SetVScrollbar, SETVSCROLLBAR, bool, visible);
|
||||
|
||||
|
||||
@ -541,9 +768,17 @@ DeclareSciCallV1(SetFoldFlags, SETFOLDFLAGS, int, flags);
|
||||
DeclareSciCallV1(FoldDisplayTextSetStyle, FOLDDISPLAYTEXTSETSTYLE, int, flags);
|
||||
DeclareSciCallR1(GetFoldParent, GETFOLDPARENT, DocLn, DocLn, line);
|
||||
DeclareSciCallR2(GetLastChild, GETLASTCHILD, DocLn, DocLn, line, int, level);
|
||||
DeclareSciCallV2(SetFoldExpanded, SETFOLDEXPANDED, DocLn, line, bool, expanded);
|
||||
DeclareSciCallR1(GetFoldExpanded, GETFOLDEXPANDED, bool, DocLn, line);
|
||||
DeclareSciCallV1(ToggleFold, TOGGLEFOLD, DocLn, line);
|
||||
DeclareSciCallV2(ToggleFoldShowText, TOGGLEFOLDSHOWTEXT, DocLn, line, const char*, text);
|
||||
DeclareSciCallV2(FoldLine, FOLDLINE, DocLn, line, int, action);
|
||||
DeclareSciCallV2(FoldChildren, FOLDCHILDREN, DocLn, line, int, action);
|
||||
DeclareSciCallV2(ExpandChildren, EXPANDCHILDREN, DocLn, line, int, level);
|
||||
DeclareSciCallV1(FoldAll, FOLDALL, int, flags);
|
||||
DeclareSciCallR0(FoldDisplayTextGetStyle, FOLDDISPLAYTEXTGETSTYLE, int);
|
||||
DeclareSciCallR1(ContractedFoldNext, CONTRACTEDFOLDNEXT, DocLn, DocLn, lineStart);
|
||||
DeclareSciCallR01(GetDefaultFoldDisplayText, GETDEFAULTFOLDDISPLAYTEXT, int, char*, text);
|
||||
DeclareSciCallV1(EnsureVisible, ENSUREVISIBLE, DocLn, line);
|
||||
DeclareSciCallV1(EnsureVisibleEnforcePolicy, ENSUREVISIBLEENFORCEPOLICY, DocLn, line);
|
||||
|
||||
@ -581,12 +816,45 @@ DeclareSciCallV2(SetStyling, SETSTYLING, DocPos, length, int, style);
|
||||
DeclareSciCallV1(StartStyling, STARTSTYLING, DocPos, position);
|
||||
DeclareSciCallR0(GetEndStyled, GETENDSTYLED, DocPos);
|
||||
|
||||
DeclareSciCallR1(StyleGetBold, STYLEGETBOLD, bool, int, style);
|
||||
DeclareSciCallR1(StyleGetItalic, STYLEGETITALIC, bool, int, style);
|
||||
DeclareSciCallR1(StyleGetSize, STYLEGETSIZE, int, int, style);
|
||||
DeclareSciCallV2(StyleSetSize, STYLESETSIZE, int, style, int, sizePoints);
|
||||
DeclareSciCallV2(StyleSetSizeFractional, STYLESETSIZEFRACTIONAL, int, style, int, sizeHundredthPoints);
|
||||
DeclareSciCallR1(StyleGetSizeFractional, STYLEGETSIZEFRACTIONAL, int, int, style);
|
||||
DeclareSciCallR1(StyleGetWeight, STYLEGETWEIGHT, int, int, style);
|
||||
DeclareSciCallV2(StyleSetEOLFilled, STYLESETEOLFILLED, int, style, bool, eolFilled);
|
||||
DeclareSciCallR1(StyleGetEOLFilled, STYLEGETEOLFILLED, bool, int, style);
|
||||
DeclareSciCallV2(StyleSetUnderline, STYLESETUNDERLINE, int, style, bool, underline);
|
||||
DeclareSciCallR1(StyleGetUnderline, STYLEGETUNDERLINE, bool, int, style);
|
||||
DeclareSciCallV2(StyleSetCase, STYLESETCASE, int, style, int, caseVisible);
|
||||
DeclareSciCallR1(StyleGetCase, STYLEGETCASE, int, int, style);
|
||||
DeclareSciCallR1(StyleGetCharacterSet, STYLEGETCHARACTERSET, int, int, style);
|
||||
DeclareSciCallR1(StyleGetVisible, STYLEGETVISIBLE, bool, int, style);
|
||||
DeclareSciCallR1(StyleGetChangeable, STYLEGETCHANGEABLE, bool, int, style);
|
||||
DeclareSciCallR1(StyleGetHotspot, STYLEGETHOTSPOT, bool, int, style);
|
||||
DeclareSciCallV2(StyleSetHotspot, STYLESETHOTSPOT, int, style, bool, hotspot);
|
||||
DeclareSciCallV1(SetHotspotActiveUnderline, SETHOTSPOTACTIVEUNDERLINE, bool, underline);
|
||||
DeclareSciCallV1(SetHotspotSigleLine, SETHOTSPOTSINGLELINE, bool, singleline);
|
||||
DeclareSciCallV2(StyleSetCheckMonospaced, STYLESETCHECKMONOSPACED, int, style, bool, checkMonospaced);
|
||||
DeclareSciCallR1(StyleGetCheckMonospaced, STYLEGETCHECKMONOSPACED, bool, int, style);
|
||||
DeclareSciCallV2(StyleSetStretch, STYLESETSTRETCH, int, style, int, stretch);
|
||||
DeclareSciCallR1(StyleGetStretch, STYLEGETSTRETCH, int, int, style);
|
||||
DeclareSciCallV2(StyleSetInvisibleRepresentation, STYLESETINVISIBLEREPRESENTATION, int, style, const char*, representation);
|
||||
DeclareSciCallR2(StyleGetInvisibleRepresentation, STYLEGETINVISIBLEREPRESENTATION, int, int, style, char*, representation);
|
||||
DeclareSciCallV2(StyleSetStrike, STYLESETSTRIKE, int, style, bool, strike);
|
||||
DeclareSciCallR1(StyleGetStrike, STYLEGETSTRIKE, bool, int, style);
|
||||
|
||||
DeclareSciCallV2(SetHotspotActiveFore, SETHOTSPOTACTIVEFORE, bool, useSetting, COLORREF, fore);
|
||||
DeclareSciCallR0(GetHotspotActiveFore, GETHOTSPOTACTIVEFORE, COLORREF);
|
||||
DeclareSciCallV2(SetHotspotActiveBack, SETHOTSPOTACTIVEBACK, bool, useSetting, COLORREF, back);
|
||||
DeclareSciCallR0(GetHotspotActiveBack, GETHOTSPOTACTIVEBACK, COLORREF);
|
||||
DeclareSciCallV1(SetHotspotActiveUnderline, SETHOTSPOTACTIVEUNDERLINE, bool, underline);
|
||||
DeclareSciCallR0(GetHotspotActiveUnderline, GETHOTSPOTACTIVEUNDERLINE, bool);
|
||||
DeclareSciCallV1(SetHotspotSingleLine, SETHOTSPOTSINGLELINE, bool, singleline);
|
||||
DeclareSciCallR0(GetHotspotSingleLine, GETHOTSPOTSINGLELINE, bool);
|
||||
|
||||
DeclareSciCallR0(GetViewWS, GETVIEWWS, int);
|
||||
DeclareSciCallV1(SetViewWS, SETVIEWWS, int, wspc);
|
||||
DeclareSciCallR0(GetViewEOL, GETVIEWEOL, bool);
|
||||
DeclareSciCallV1(SetViewEOL, SETVIEWEOL, bool, eols);
|
||||
|
||||
DeclareSciCallR2(StyleGetFont, STYLEGETFONT, int, int, style, char*, fontname);
|
||||
@ -610,8 +878,11 @@ DeclareSciCallV1(SetWrapMode, SETWRAPMODE, int, mode);
|
||||
DeclareSciCallR0(GetWrapMode, GETWRAPMODE, int);
|
||||
DeclareSciCallV1(SetWrapIndentMode, SETWRAPINDENTMODE, int, mode);
|
||||
DeclareSciCallR0(GetWrapIndentMode, GETWRAPINDENTMODE, int);
|
||||
DeclareSciCallR0(GetWrapStartIndent, GETWRAPSTARTINDENT, int);
|
||||
DeclareSciCallV1(SetWrapStartIndent, SETWRAPSTARTINDENT, int, mode);
|
||||
DeclareSciCallR0(GetWrapVisualFlags, GETWRAPVISUALFLAGS, int);
|
||||
DeclareSciCallV1(SetWrapVisualFlags, SETWRAPVISUALFLAGS, int, opts);
|
||||
DeclareSciCallR0(GetWrapVisualFlagsLocation, GETWRAPVISUALFLAGSLOCATION, int);
|
||||
DeclareSciCallV1(SetWrapVisualFlagsLocation, SETWRAPVISUALFLAGSLOCATION, int, opts);
|
||||
DeclareSciCallR1(WrapCount, WRAPCOUNT, DocLn, DocLn, line);
|
||||
DeclareSciCallR0(GetIndentationGuides, GETINDENTATIONGUIDES, int);
|
||||
@ -644,6 +915,11 @@ DeclareSciCallR1(GetLineIndentPosition, GETLINEINDENTPOSITION, DocPos, DocLn, li
|
||||
|
||||
DeclareSciCallV1(SetIndentationGuides, SETINDENTATIONGUIDES, int, iview);
|
||||
DeclareSciCallV1(SetHighLightGuide, SETHIGHLIGHTGUIDE, int, column);
|
||||
DeclareSciCallR0(GetHighlightGuide, GETHIGHLIGHTGUIDE, DocPos);
|
||||
// Tab Stops
|
||||
DeclareSciCallV1(ClearTabStops, CLEARTABSTOPS, DocLn, line);
|
||||
DeclareSciCallV2(AddTabStop, ADDTABSTOP, DocLn, line, int, x);
|
||||
DeclareSciCallR2(GetNextTabStop, GETNEXTTABSTOP, int, DocLn, line, int, x);
|
||||
|
||||
DeclareSciCallR1(BraceMatch, BRACEMATCH, DocPos, DocPos, pos);
|
||||
DeclareSciCallR2(BraceMatchNext, BRACEMATCHNEXT, DocPos, DocPos, pos, DocPos, posStart);
|
||||
@ -657,18 +933,26 @@ DeclareSciCallV2(BraceBadLightIndicator, BRACEBADLIGHTINDICATOR, bool, use, int,
|
||||
//
|
||||
// Margins
|
||||
//
|
||||
DeclareSciCallR0(GetMarginOptions, GETMARGINOPTIONS, int);
|
||||
DeclareSciCallV1(SetMarginOptions, SETMARGINOPTIONS, int, options);
|
||||
DeclareSciCallR1(GetMarginTypeN, GETMARGINTYPEN, int, int, margin);
|
||||
DeclareSciCallV2(SetMarginTypeN, SETMARGINTYPEN, uintptr_t, margin, int, type);
|
||||
DeclareSciCallR1(GetMarginWidthN, GETMARGINWIDTHN, int, uintptr_t, margin);
|
||||
DeclareSciCallV2(SetMarginWidthN, SETMARGINWIDTHN, uintptr_t, margin, int, pixelWidth);
|
||||
DeclareSciCallR1(GetMarginMaskN, GETMARGINMASKN, int, int, margin);
|
||||
DeclareSciCallV2(SetMarginMaskN, SETMARGINMASKN, uintptr_t, margin, int, mask);
|
||||
DeclareSciCallR1(GetMarginSensitiveN, GETMARGINSENSITIVEN, bool, int, margin);
|
||||
DeclareSciCallV2(SetMarginSensitiveN, SETMARGINSENSITIVEN, uintptr_t, margin, bool, sensitive);
|
||||
DeclareSciCallV2(SetMarginBackN, SETMARGINBACKN, uintptr_t, margin, COLORREF, colour);
|
||||
DeclareSciCallR1(GetMarginCursorN, GETMARGINCURSORN, int, int, margin);
|
||||
DeclareSciCallV2(SetMarginCursorN, SETMARGINCURSORN, uintptr_t, margin, int, cursor);
|
||||
DeclareSciCallR1(GetMarginBackN, GETMARGINBACKN, COLORREF, int, margin);
|
||||
DeclareSciCallV2(SetMarginBackN, SETMARGINBACKN, uintptr_t, margin, COLORREF, colour);
|
||||
DeclareSciCallV2(SetFoldMarginColour, SETFOLDMARGINCOLOUR, bool, useSetting, COLORREF, colour);
|
||||
DeclareSciCallV2(SetFoldMarginHiColour, SETFOLDMARGINHICOLOUR, bool, useSetting, COLORREF, colour);
|
||||
DeclareSciCallV01(SetDefaultFoldDisplayText, SETDEFAULTFOLDDISPLAYTEXT, const char*, text);
|
||||
DeclareSciCallR0(GetMarginLeft, GETMARGINLEFT, int);
|
||||
DeclareSciCallV01(SetMarginLeft, SETMARGINLEFT, int, width);
|
||||
DeclareSciCallR0(GetMarginRight, GETMARGINRIGHT, int);
|
||||
DeclareSciCallV01(SetMarginRight, SETMARGINRIGHT, int, width);
|
||||
|
||||
DeclareSciCallR2(TextWidth, TEXTWIDTH, int, int, styleNumber, const char *, text);
|
||||
@ -687,8 +971,14 @@ DeclareSciCallV2(MarkerSetBackSelected, MARKERSETBACKSELECTED, int, markerID, CO
|
||||
DeclareSciCallV2(MarkerSetBackSelectedTranslucent, MARKERSETBACKSELECTEDTRANSLUCENT, int, markerID, COLORALPHAREF, colouralpha);
|
||||
DeclareSciCallV2(MarkerSetStrokeWidth, MARKERSETSTROKEWIDTH, int, markerID, int, hundredths);
|
||||
DeclareSciCallV1(MarkerEnableHighlight, MARKERENABLEHIGHLIGHT, bool, flag);
|
||||
DeclareSciCallR1(MarkerGetLayer, MARKERGETLAYER, int, int, markerNumber);
|
||||
DeclareSciCallV2(MarkerSetLayer, MARKERSETLAYER, int, markerID, int, layer);
|
||||
DeclareSciCallV2(MarkerSetAlpha, MARKERSETALPHA, int, markerID, int, alpha);
|
||||
DeclareSciCallR1(MarkerSymbolDefined, MARKERSYMBOLDEFINED, int, int, markerNumber);
|
||||
DeclareSciCallR1(MarkerLineFromHandle, MARKERLINEFROMHANDLE, DocLn, int, markerHandle);
|
||||
DeclareSciCallV1(MarkerDeleteHandle, MARKERDELETEHANDLE, int, markerHandle);
|
||||
DeclareSciCallV2(MarkerDefinePixmap, MARKERDEFINEPIXMAP, int, markerNumber, const char*, pixmap);
|
||||
DeclareSciCallV2(MarkerDefineRGBAImage, MARKERDEFINERGBAIMAGE, int, markerNumber, const char*, pixels);
|
||||
DeclareSciCallR2(MarkerAdd, MARKERADD, int, DocLn, line, int, markerID);
|
||||
DeclareSciCallV2(MarkerAddSet, MARKERADDSET, DocLn, line, int, markerMask);
|
||||
DeclareSciCallV2(MarkerDelete, MARKERDELETE, DocLn, line, int, markerID);
|
||||
@ -711,15 +1001,29 @@ DeclareSciCallR1(IndicGetStrokeWidth, INDICGETSTROKEWIDTH, int, int, indicID);
|
||||
DeclareSciCallV2(IndicSetUnder, INDICSETUNDER, int, indicID, bool, under);
|
||||
DeclareSciCallR1(IndicGetUnder, INDICGETUNDER, bool, int, indicID);
|
||||
DeclareSciCallV2(IndicSetHoverStyle, INDICSETHOVERSTYLE, int, indicID, int, style);
|
||||
DeclareSciCallR1(IndicGetHoverStyle, INDICGETHOVERSTYLE, int, int, indicator);
|
||||
DeclareSciCallV2(IndicSetHoverFore, INDICSETHOVERFORE, int, indicID, COLORREF, colour);
|
||||
DeclareSciCallR1(IndicGetHoverFore, INDICGETHOVERFORE, COLORREF, int, indicator);
|
||||
DeclareSciCallV2(IndicSetAlpha, INDICSETALPHA, int, indicID, int, alpha);
|
||||
DeclareSciCallR1(IndicGetAlpha, INDICGETALPHA, int, int, indicator);
|
||||
DeclareSciCallV2(IndicSetOutlineAlpha, INDICSETOUTLINEALPHA, int, indicID, int, alpha);
|
||||
DeclareSciCallR1(IndicGetOutlineAlpha, INDICGETOUTLINEALPHA, int, int, indicator);
|
||||
DeclareSciCallV2(IndicSetFlags, INDICSETFLAGS, int, indicator, int, flags);
|
||||
DeclareSciCallR1(IndicGetFlags, INDICGETFLAGS, int, int, indicator);
|
||||
DeclareSciCallV1(SetIndicatorCurrent, SETINDICATORCURRENT, int, indicID);
|
||||
DeclareSciCallR0(GetIndicatorCurrent, GETINDICATORCURRENT, int);
|
||||
DeclareSciCallV1(SetIndicatorValue, SETINDICATORVALUE, int, value);
|
||||
DeclareSciCallR0(GetIndicatorValue, GETINDICATORVALUE, int);
|
||||
DeclareSciCallV2(IndicatorFillRange, INDICATORFILLRANGE, DocPos, position, DocPos, length);
|
||||
DeclareSciCallV2(IndicatorClearRange, INDICATORCLEARRANGE, DocPos, position, DocPos, length);
|
||||
DeclareSciCallR1(IndicatorAllOnFor, INDICATORALLONFOR, int, DocPos, pos);
|
||||
DeclareSciCallR2(IndicatorValueAt, INDICATORVALUEAT, int, int, indicID, DocPos, position);
|
||||
DeclareSciCallR2(IndicatorStart, INDICATORSTART, int, int, indicID, DocPos, position);
|
||||
DeclareSciCallR2(IndicatorEnd, INDICATOREND, int, int, indicID, DocPos, position);
|
||||
// macOS Find Indicator
|
||||
DeclareSciCallV2(FindIndicatorShow, FINDINDICATORSHOW, DocPos, start, DocPos, end);
|
||||
DeclareSciCallV2(FindIndicatorFlash, FINDINDICATORFLASH, DocPos, start, DocPos, end);
|
||||
DeclareSciCallV0(FindIndicatorHide, FINDINDICATORHIDE);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
@ -727,8 +1031,18 @@ DeclareSciCallR2(IndicatorEnd, INDICATOREND, int, int, indicID, DocPos, position
|
||||
// Lexer
|
||||
//
|
||||
DeclareSciCallV2(SetProperty, SETPROPERTY, const char*, key, const char*, value);
|
||||
DeclareSciCallR2(GetProperty, GETPROPERTY, int, const char*, key, char*, value);
|
||||
DeclareSciCallR2(GetPropertyExpanded, GETPROPERTYEXPANDED, int, const char*, key, char*, value);
|
||||
DeclareSciCallR2(GetPropertyInt, GETPROPERTYINT, int, const char*, key, int, defaultValue);
|
||||
DeclareSciCallV2(SetKeywords, SETKEYWORDS, int, keywordset, const char*, keywords);
|
||||
DeclareSciCallV2(Colourise, COLOURISE, DocPos, startPos, DocPos, endPos);
|
||||
DeclareSciCallR01(GetLexerLanguage, GETLEXERLANGUAGE, int, char*, language);
|
||||
DeclareSciCallR2(PrivateLexerCall, PRIVATELEXERCALL, sptr_t, int, operation, sptr_t, pointer);
|
||||
DeclareSciCallR01(PropertyNames, PROPERTYNAMES, int, char*, names);
|
||||
DeclareSciCallR1(PropertyType, PROPERTYTYPE, int, const char*, name);
|
||||
DeclareSciCallR2(DescribeProperty, DESCRIBEPROPERTY, int, const char*, name, char*, description);
|
||||
DeclareSciCallR01(DescribeKeyWordSets, DESCRIBEKEYWORDSETS, int, char*, descriptions);
|
||||
DeclareSciCallR0(GetLineEndTypesSupported, GETLINEENDTYPESSUPPORTED, int);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
@ -737,8 +1051,11 @@ DeclareSciCallV2(Colourise, COLOURISE, DocPos, startPos, DocPos, endPos);
|
||||
//
|
||||
DeclareSciCallV1(SetCursor, SETCURSOR, int, flags);
|
||||
|
||||
DeclareSciCallR0(GetCaretStyle, GETCARETSTYLE, int);
|
||||
DeclareSciCallV1(SetCaretStyle, SETCARETSTYLE, int, style);
|
||||
DeclareSciCallR0(GetCaretWidth, GETCARETWIDTH, int);
|
||||
DeclareSciCallV1(SetCaretWidth, SETCARETWIDTH, int, pixel);
|
||||
DeclareSciCallR0(GetCaretPeriod, GETCARETPERIOD, int);
|
||||
DeclareSciCallV1(SetCaretPeriod, SETCARETPERIOD, int, msec);
|
||||
DeclareSciCallV1(SetAdditionalCaretsBlink, SETADDITIONALCARETSBLINK, bool, flag);
|
||||
DeclareSciCallV1(SetAdditionalCaretsVisible, SETADDITIONALCARETSVISIBLE, bool, flag);
|
||||
@ -754,6 +1071,20 @@ DeclareSciCallV0(EndUndoAction, ENDUNDOACTION);
|
||||
DeclareSciCallR0(GetUndoCollection, GETUNDOCOLLECTION, bool);
|
||||
DeclareSciCallV1(SetUndoCollection, SETUNDOCOLLECTION, bool, bCollectUndo);
|
||||
DeclareSciCallR0(GetUndoSequence, GETUNDOSEQUENCE, int);
|
||||
DeclareSciCallR0(GetUndoActions, GETUNDOACTIONS, int);
|
||||
DeclareSciCallV1(SetUndoSavePoint, SETUNDOSAVEPOINT, int, action);
|
||||
DeclareSciCallR0(GetUndoSavePoint, GETUNDOSAVEPOINT, int);
|
||||
DeclareSciCallV1(SetUndoDetach, SETUNDODETACH, int, action);
|
||||
DeclareSciCallR0(GetUndoDetach, GETUNDODETACH, int);
|
||||
DeclareSciCallV1(SetUndoTentative, SETUNDOTENTATIVE, int, action);
|
||||
DeclareSciCallR0(GetUndoTentative, GETUNDOTENTATIVE, int);
|
||||
DeclareSciCallV1(SetUndoCurrent, SETUNDOCURRENT, int, action);
|
||||
DeclareSciCallR0(GetUndoCurrent, GETUNDOCURRENT, int);
|
||||
DeclareSciCallV2(PushUndoActionType, PUSHUNDOACTIONTYPE, int, type, DocPos, pos);
|
||||
DeclareSciCallV2(ChangeLastUndoActionText, CHANGELASTUNDOACTIONTEXT, DocPos, length, const char*, text);
|
||||
DeclareSciCallR1(GetUndoActionType, GETUNDOACTIONTYPE, int, int, action);
|
||||
DeclareSciCallR1(GetUndoActionPosition, GETUNDOACTIONPOSITION, DocPos, int, action);
|
||||
DeclareSciCallR2(GetUndoActionText, GETUNDOACTIONTEXT, int, int, action, char*, text);
|
||||
DeclareSciCallV1(SetUndoSelectionHistory, SETUNDOSELECTIONHISTORY, int, option);
|
||||
DeclareSciCallR0(GetUndoSelectionHistory, GETUNDOSELECTIONHISTORY, int);
|
||||
|
||||
@ -762,11 +1093,111 @@ DeclareSciCallR0(GetUndoSelectionHistory, GETUNDOSELECTIONHISTORY, int);
|
||||
//
|
||||
// IME
|
||||
//
|
||||
DeclareSciCallR0(GetIMEInteraction, GETIMEINTERACTION, int);
|
||||
DeclareSciCallV1(SetIMEInteraction, SETIMEINTERACTION, int, interact);
|
||||
DeclareSciCallR0(IsIMEOpen, ISIMEOPEN, bool);
|
||||
DeclareSciCallR0(IsIMEModeCJK, ISIMEMODECJK, bool);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Annotations
|
||||
//
|
||||
DeclareSciCallV2(AnnotationSetText, ANNOTATIONSETTEXT, DocLn, line, const char*, text);
|
||||
DeclareSciCallR2(AnnotationGetText, ANNOTATIONGETTEXT, int, DocLn, line, char*, text);
|
||||
DeclareSciCallV2(AnnotationSetStyle, ANNOTATIONSETSTYLE, DocLn, line, int, style);
|
||||
DeclareSciCallR1(AnnotationGetStyle, ANNOTATIONGETSTYLE, int, DocLn, line);
|
||||
DeclareSciCallV2(AnnotationSetStyles, ANNOTATIONSETSTYLES, DocLn, line, const char*, styles);
|
||||
DeclareSciCallR2(AnnotationGetStyles, ANNOTATIONGETSTYLES, int, DocLn, line, char*, styles);
|
||||
DeclareSciCallR1(AnnotationGetLines, ANNOTATIONGETLINES, int, DocLn, line);
|
||||
DeclareSciCallV0(AnnotationClearAll, ANNOTATIONCLEARALL);
|
||||
DeclareSciCallV1(AnnotationSetVisible, ANNOTATIONSETVISIBLE, int, visible);
|
||||
DeclareSciCallR0(AnnotationGetVisible, ANNOTATIONGETVISIBLE, int);
|
||||
DeclareSciCallV1(AnnotationSetStyleOffset, ANNOTATIONSETSTYLEOFFSET, int, style);
|
||||
DeclareSciCallR0(AnnotationGetStyleOffset, ANNOTATIONGETSTYLEOFFSET, int);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// EOL Annotations
|
||||
//
|
||||
DeclareSciCallV2(EOLAnnotationSetText, EOLANNOTATIONSETTEXT, DocLn, line, const char*, text);
|
||||
DeclareSciCallR2(EOLAnnotationGetText, EOLANNOTATIONGETTEXT, int, DocLn, line, char*, text);
|
||||
DeclareSciCallV2(EOLAnnotationSetStyle, EOLANNOTATIONSETSTYLE, DocLn, line, int, style);
|
||||
DeclareSciCallR1(EOLAnnotationGetStyle, EOLANNOTATIONGETSTYLE, int, DocLn, line);
|
||||
DeclareSciCallV0(EOLAnnotationClearAll, EOLANNOTATIONCLEARALL);
|
||||
DeclareSciCallV1(EOLAnnotationSetVisible, EOLANNOTATIONSETVISIBLE, int, visible);
|
||||
DeclareSciCallR0(EOLAnnotationGetVisible, EOLANNOTATIONGETVISIBLE, int);
|
||||
DeclareSciCallV1(EOLAnnotationSetStyleOffset, EOLANNOTATIONSETSTYLEOFFSET, int, style);
|
||||
DeclareSciCallR0(EOLAnnotationGetStyleOffset, EOLANNOTATIONGETSTYLEOFFSET, int);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Margin Text
|
||||
//
|
||||
DeclareSciCallV2(MarginSetText, MARGINSETTEXT, DocLn, line, const char*, text);
|
||||
DeclareSciCallR2(MarginGetText, MARGINGETTEXT, int, DocLn, line, char*, text);
|
||||
DeclareSciCallV2(MarginSetStyle, MARGINSETSTYLE, DocLn, line, int, style);
|
||||
DeclareSciCallR1(MarginGetStyle, MARGINGETSTYLE, int, DocLn, line);
|
||||
DeclareSciCallV2(MarginSetStyles, MARGINSETSTYLES, DocLn, line, const char*, styles);
|
||||
DeclareSciCallR2(MarginGetStyles, MARGINGETSTYLES, int, DocLn, line, char*, styles);
|
||||
DeclareSciCallV0(MarginTextClearAll, MARGINTEXTCLEARALL);
|
||||
DeclareSciCallV1(MarginSetStyleOffset, MARGINSETSTYLEOFFSET, int, style);
|
||||
DeclareSciCallR0(MarginGetStyleOffset, MARGINGETSTYLEOFFSET, int);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Substyles
|
||||
//
|
||||
DeclareSciCallR2(AllocateSubStyles, ALLOCATESUBSTYLES, int, int, styleBase, int, numberStyles);
|
||||
DeclareSciCallR1(GetSubStylesStart, GETSUBSTYLESSTART, int, int, styleBase);
|
||||
DeclareSciCallR1(GetSubStylesLength, GETSUBSTYLESLENGTH, int, int, styleBase);
|
||||
DeclareSciCallV0(FreeSubStyles, FREESUBSTYLES);
|
||||
DeclareSciCallV2(SetIdentifiers, SETIDENTIFIERS, int, style, const char*, identifiers);
|
||||
DeclareSciCallR0(DistanceToSecondaryStyles, DISTANCETOSECONDARYSTYLES, int);
|
||||
DeclareSciCallR01(GetSubStyleBases, GETSUBSTYLEBASES, int, char*, styles);
|
||||
DeclareSciCallR1(GetStyleFromSubStyle, GETSTYLEFROMSUBSTYLE, int, int, subStyle);
|
||||
DeclareSciCallR1(GetPrimaryStyleFromStyle, GETPRIMARYSTYLEFROMSTYLE, int, int, style);
|
||||
DeclareSciCallR0(GetNamedStyles, GETNAMEDSTYLES, int);
|
||||
DeclareSciCallR2(NameOfStyle, NAMEOFSTYLE, int, int, style, char*, name);
|
||||
DeclareSciCallR2(TagsOfStyle, TAGSOFSTYLE, int, int, style, char*, tags);
|
||||
DeclareSciCallR2(DescriptionOfStyle, DESCRIPTIONOFSTYLE, int, int, style, char*, description);
|
||||
DeclareSciCallV0(ReleaseAllExtendedStyles, RELEASEALLEXTENDEDSTYLES);
|
||||
DeclareSciCallR1(AllocateExtendedStyles, ALLOCATEEXTENDEDSTYLES, int, int, numberStyles);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Printing
|
||||
//
|
||||
DeclareSciCallV1(SetPrintMagnification, SETPRINTMAGNIFICATION, int, magnification);
|
||||
DeclareSciCallR0(GetPrintMagnification, GETPRINTMAGNIFICATION, int);
|
||||
DeclareSciCallV1(SetPrintColourMode, SETPRINTCOLOURMODE, int, mode);
|
||||
DeclareSciCallR0(GetPrintColourMode, GETPRINTCOLOURMODE, int);
|
||||
DeclareSciCallV1(SetPrintWrapMode, SETPRINTWRAPMODE, int, wrapMode);
|
||||
DeclareSciCallR0(GetPrintWrapMode, GETPRINTWRAPMODE, int);
|
||||
DeclareSciCallR2(FormatRange, FORMATRANGE, DocPos, bool, draw, struct Sci_RangeToFormat*, fr);
|
||||
DeclareSciCallR2(FormatRangeFull, FORMATRANGEFULL, DocPos, bool, draw, struct Sci_RangeToFormatFull*, fr);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Recording
|
||||
//
|
||||
DeclareSciCallV0(StartRecord, STARTRECORD);
|
||||
DeclareSciCallV0(StopRecord, STOPRECORD);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Drag and Drop
|
||||
//
|
||||
DeclareSciCallR0(GetDragDropEnabled, GETDRAGDROPENABLED, bool);
|
||||
DeclareSciCallV1(SetDragDropEnabled, SETDRAGDROPENABLED, bool, dragDropEnabled);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Utilities
|
||||
|
||||
@ -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
11
src/timsort/AUTHORS
Normal 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
202
src/timsort/LICENSE
Normal 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
156
src/timsort/README.md
Normal 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
166
src/timsort/stresstest.c
Normal 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
837
src/timsort/timsort-impl.h
Normal 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
423
src/timsort/timsort.c
Normal 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
65
src/timsort/timsort.h
Normal 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
18
src/timsort/timsort_r.c
Normal 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"
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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; \
|
||||
|
||||
@ -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 { \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user