Skip to content

Commit

Permalink
Code cleanup: Sorting (#83017)
Browse files Browse the repository at this point in the history
## About The Pull Request
1. Removes code duplication 
2. Fully documents `sortTim()`
3. Makes a define with default sortTim behavior, straight and to the
point for 95% of cases
4. Migrates other sorts into the same file
5. Removes some redundancy where they're reassigning a variable using an
in place sorter

For the record, we only use timSort
## Why It's Good For The Game
More documentation, easier to read, uses `length` over `len`, etc
Should be no gameplay effect at all
  • Loading branch information
jlsnow301 committed May 5, 2024
1 parent 618bd42 commit e766f92
Show file tree
Hide file tree
Showing 17 changed files with 108 additions and 73 deletions.
2 changes: 1 addition & 1 deletion code/__HELPERS/hallucinations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ ADMIN_VERB(debug_hallucination_weighted_list_per_type, R_DEBUG, "Show Hallucinat
last_type_weight = this_weight

// Sort by weight descending, where weight is the values (not the keys). We assoc_to_keys later to get JUST the text
all_weights = sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)

var/page_style = "<style>table, th, td {border: 1px solid black;border-collapse: collapse;}</style>"
var/page_contents = "[page_style]<table style=\"width:100%\">[header][jointext(assoc_to_keys(all_weights), "")]</table>"
Expand Down
19 changes: 0 additions & 19 deletions code/__HELPERS/sorts/InsertSort.dm

This file was deleted.

19 changes: 0 additions & 19 deletions code/__HELPERS/sorts/MergeSort.dm

This file was deleted.

20 changes: 0 additions & 20 deletions code/__HELPERS/sorts/TimSort.dm

This file was deleted.

95 changes: 95 additions & 0 deletions code/__HELPERS/sorts/helpers.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/// Sorts the list in place with timSort, default settings.
#define SORT_TIM(to_sort, associative) if(length(to_sort) >= 2) { \
var/datum/sort_instance/sorter = GLOB.sortInstance; \
if (isnull(sorter)) { \
sorter = new; \
} \
sorter.L = to_sort; \
sorter.cmp = GLOBAL_PROC_REF(cmp_numeric_asc); \
sorter.associative = associative; \
sorter.timSort(1, 0); \
}


/// Helper for the sorting procs. Prevents some code duplication. Creates /datum/sort_instance/sorter
#define CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) \
if(length(to_sort) < 2) { \
return to_sort; \
} \
fromIndex = fromIndex % length(to_sort); \
toIndex = toIndex % (length(to_sort) + 1); \
if (fromIndex <= 0) { \
fromIndex += length(to_sort); \
} \
if (toIndex <= 0) { \
toIndex += length(to_sort) + 1; \
} \
var/datum/sort_instance/sorter = GLOB.sortInstance; \
if (isnull(sorter)) { \
sorter = new; \
} \
sorter.L = to_sort; \
sorter.cmp = cmp; \
sorter.associative = associative;


/**
* ## Tim Sort
* Hybrid sorting algorithm derived from merge sort and insertion sort.
*
* **Sorts in place**.
* You might not need to get the return value.
*
* @see
* https://en.wikipedia.org/wiki/Timsort
*
* @param {list} to_sort - The list to sort.
*
* @param {proc} cmp - The comparison proc to use. Default: Numeric ascending.
*
* @param {boolean} associative - Whether the list is associative. Default: FALSE.
*
* @param {int} fromIndex - The index to start sorting from. Default: 1.
*
* @param {int} toIndex - The index to stop sorting at. Default: 0.
*/
/proc/sortTim(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)

sorter.timSort(fromIndex, toIndex)

return to_sort


/**
* ## Merge Sort
* Divide and conquer sorting algorithm.
*
* @see
* - https://en.wikipedia.org/wiki/Merge_sort
*/
/proc/sortMerge(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)

sorter.mergeSort(fromIndex, toIndex)

return to_sort


/**
* ## Insertion Sort
* Simple sorting algorithm that builds the final sorted list one item at a time.
*
* @see
* - https://en.wikipedia.org/wiki/Insertion_sort
*/
/proc/sortInsert(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)

sorter.binarySort(fromIndex, toIndex)

return to_sort


#undef CREATE_SORT_INSTANCE
File renamed without changes.
2 changes: 1 addition & 1 deletion code/controllers/subsystem/dcs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ PROCESSING_SUBSYSTEM_DEF(dcs)
fullid += REF(key)

if(named_arguments)
named_arguments = sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc))
sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc))
fullid += named_arguments

return list2params(fullid)
Expand Down
2 changes: 1 addition & 1 deletion code/datums/datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
atom_cast.filters = null
filter_data = sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
for(var/filter_raw in filter_data)
var/list/data = filter_data[filter_raw]
var/list/arguments = data.Copy()
Expand Down
2 changes: 1 addition & 1 deletion code/modules/admin/verbs/debug.dm
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ ADMIN_VERB(reestablish_tts_connection, R_DEBUG, "Re-establish Connection To TTS"
var/list/sorted = list()
for (var/source in per_source)
sorted += list(list("source" = source, "count" = per_source[source]))
sorted = sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data))
sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data))

// Now that everything is sorted, compile them into an HTML output
var/output = "<table border='1'>"
Expand Down
2 changes: 1 addition & 1 deletion code/modules/admin/verbs/light_debug.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
sum[source.source_atom.type] += 1
total += 1

sum = sortTim(sum, /proc/cmp_numeric_asc, TRUE)
sortTim(sum, associative = TRUE)
var/text = ""
for(var/type in sum)
text += "[type] = [sum[type]]\n"
Expand Down
2 changes: 1 addition & 1 deletion code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
filtered_modules[AM.category][AM] = AM

for(var/category in filtered_modules)
filtered_modules[category] = sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority))
sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority))

return filtered_modules

Expand Down
2 changes: 1 addition & 1 deletion code/modules/antagonists/pirate/pirate.dm
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
//Lists notable loot.
if(!cargo_hold || !cargo_hold.total_report)
return "Nothing"
cargo_hold.total_report.total_value = sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
var/count = 0
var/list/loot_texts = list()
for(var/datum/export/E in cargo_hold.total_report.total_value)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/asset_cache/assets/uplink.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
var/list/items = list()
for(var/datum/uplink_category/category as anything in subtypesof(/datum/uplink_category))
categories += category
categories = sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc))
sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc))

var/list/new_categories = list()
for(var/datum/uplink_category/category as anything in categories)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/datum/computer_file/program/emojipedia/New()
. = ..()
// Sort the emoji list so it's easier to find things and we don't have to keep sorting on ui_data since the number of emojis can not change in-game.
emoji_list = sortTim(emoji_list, /proc/cmp_text_asc)
sortTim(emoji_list, /proc/cmp_text_asc)

/datum/computer_file/program/emojipedia/ui_static_data(mob_user)
var/list/data = list()
Expand Down
2 changes: 1 addition & 1 deletion code/modules/research/stock_parts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
continue
part_list += component_part
//Sort the parts. This ensures that higher tier items are applied first.
part_list = sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
return part_list

/proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/unit_tests/unit_test.dm
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
if(length(focused_tests))
tests_to_run = focused_tests

tests_to_run = sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))
sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))

var/list/test_results = list()

Expand Down
6 changes: 2 additions & 4 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -504,10 +504,8 @@
#include "code\__HELPERS\paths\jps.dm"
#include "code\__HELPERS\paths\path.dm"
#include "code\__HELPERS\paths\sssp.dm"
#include "code\__HELPERS\sorts\__main.dm"
#include "code\__HELPERS\sorts\InsertSort.dm"
#include "code\__HELPERS\sorts\MergeSort.dm"
#include "code\__HELPERS\sorts\TimSort.dm"
#include "code\__HELPERS\sorts\helpers.dm"
#include "code\__HELPERS\sorts\sort_instance.dm"
#include "code\_globalvars\_regexes.dm"
#include "code\_globalvars\admin.dm"
#include "code\_globalvars\arcade.dm"
Expand Down

0 comments on commit e766f92

Please sign in to comment.