2021-02-20 14:03:54 +00:00
package hyphae
2021-10-01 17:12:16 +00:00
// 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 {
2022-02-04 14:56:28 +00:00
switch h . ( type ) {
default :
2021-02-20 14:03:54 +00:00
ch <- h
}
}
close ( ch )
} ( )
return ch
}
2022-01-30 21:34:52 +00:00
// 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 {
2022-01-30 21:34:52 +00:00
// 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 ( ) {
2022-02-03 21:47:36 +00:00
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 {
2022-02-03 21:47:36 +00:00
if hn == h . CanonicalName ( ) {
2021-02-20 14:03:54 +00:00
return hn , false
}
}
}
return "" , true
}