1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 11:46:16 +00:00
mycorrhiza/hyphae/iterators.go

113 lines
2.6 KiB
Go
Raw Normal View History

2021-02-20 14:03:54 +00:00
package hyphae
// File `iterators.go` contains stuff that iterates over hyphae.
2021-02-20 14:03:54 +00:00
import (
2021-08-31 17:12:55 +00:00
"sort"
2021-09-23 09:36:54 +00:00
"strings"
2022-02-04 11:14:53 +00:00
"sync"
2021-02-20 14:03:54 +00:00
)
2022-02-19 08:26:38 +00:00
var byNames = make(map[string]ExistingHypha)
2022-02-04 11:14:53 +00:00
var byNamesMutex = sync.Mutex{}
2021-02-20 14:03:54 +00:00
// YieldExistingHyphae iterates over all hyphae and yields all existing ones.
2022-02-19 08:26:38 +00:00
func YieldExistingHyphae() chan ExistingHypha {
ch := make(chan ExistingHypha)
2021-02-20 14:03:54 +00:00
go func() {
for _, h := range byNames {
switch h.(type) {
default:
2021-02-20 14:03:54 +00:00
ch <- h
}
}
close(ch)
}()
return ch
}
// FilterHyphaeWithText filters the source channel and yields only those hyphae than have text parts.
2022-02-19 08:26:38 +00:00
func FilterHyphaeWithText(src chan ExistingHypha) chan ExistingHypha {
// TODO: reimplement as a function with a callback?
2022-02-19 08:26:38 +00:00
sink := make(chan ExistingHypha)
2021-02-20 14:03:54 +00:00
go func() {
for h := range src {
2022-02-19 08:26:38 +00:00
switch h := h.(type) {
case *TextualHypha:
2021-02-20 14:03:54 +00:00
sink <- h
2022-02-19 08:26:38 +00:00
case *MediaHypha:
if h.HasTextFile() {
sink <- h
}
2021-02-20 14:03:54 +00:00
}
}
close(sink)
}()
return sink
}
2021-08-31 17:12:55 +00:00
// PathographicSort sorts paths inside the source channel, preserving the path tree structure
func PathographicSort(src chan string) <-chan string {
out := make(chan string)
go func() {
// To make it unicode-friendly and lean, we cast every string into rune slices, sort, and only then cast them back
raw := make([][]rune, 0)
for h := range src {
raw = append(raw, []rune(h))
}
sort.Slice(raw, func(i, j int) bool {
const slash rune = 47 // == '/'
// Classic lexicographical sort with a twist
c := 0
for {
2021-09-23 09:36:54 +00:00
if c == len(raw[i]) {
return true
}
if c == len(raw[j]) {
return false
}
2021-08-31 17:12:55 +00:00
if raw[i][c] == raw[j][c] {
c++
} else {
// The twist: subhyphae-awareness is about pushing slash upwards
2021-09-23 09:36:54 +00:00
if raw[i][c] == slash {
return true
}
if raw[j][c] == slash {
return false
}
2021-08-31 17:12:55 +00:00
return raw[i][c] < raw[j][c]
}
}
})
for _, name := range raw {
out <- string(name)
}
close(out)
}()
return out
}
2021-02-20 14:03:54 +00:00
// Subhyphae returns slice of subhyphae.
2022-02-19 08:26:38 +00:00
func Subhyphae(h Hypha) []ExistingHypha {
var hyphae []ExistingHypha
2021-02-20 14:03:54 +00:00
for subh := range YieldExistingHyphae() {
if strings.HasPrefix(subh.CanonicalName(), h.CanonicalName()+"/") {
2021-02-20 14:03:54 +00:00
hyphae = append(hyphae, subh)
}
}
return hyphae
}
// AreFreeNames checks if all given `hyphaNames` are not taken. If they are not taken, `ok` is true. If not, `firstFailure` is the name of the first met hypha that is not free.
func AreFreeNames(hyphaNames ...string) (firstFailure string, ok bool) {
for h := range YieldExistingHyphae() {
for _, hn := range hyphaNames {
if hn == h.CanonicalName() {
2021-02-20 14:03:54 +00:00
return hn, false
}
}
}
return "", true
}