mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 18:22:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			100 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			100 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package mempool
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"unsafe"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const DefaultDirtyFactor = 128
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Pool provides a type-safe form
							 | 
						||
| 
								 | 
							
								// of UnsafePool using generics.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note it is NOT safe for concurrent
							 | 
						||
| 
								 | 
							
								// use, you must protect it yourself!
							 | 
						||
| 
								 | 
							
								type Pool[T any] struct {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// New is an optionally provided
							 | 
						||
| 
								 | 
							
									// allocator used when no value
							 | 
						||
| 
								 | 
							
									// is available for use in pool.
							 | 
						||
| 
								 | 
							
									New func() T
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Reset is an optionally provided
							 | 
						||
| 
								 | 
							
									// value resetting function called
							 | 
						||
| 
								 | 
							
									// on passed value to Put().
							 | 
						||
| 
								 | 
							
									Reset func(T)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									UnsafePool
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *Pool[T]) Get() T {
							 | 
						||
| 
								 | 
							
									if ptr := p.UnsafePool.Get(); ptr != nil {
							 | 
						||
| 
								 | 
							
										return *(*T)(ptr)
							 | 
						||
| 
								 | 
							
									} else if p.New != nil {
							 | 
						||
| 
								 | 
							
										return p.New()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var z T
							 | 
						||
| 
								 | 
							
									return z
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *Pool[T]) Put(t T) {
							 | 
						||
| 
								 | 
							
									if p.Reset != nil {
							 | 
						||
| 
								 | 
							
										p.Reset(t)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									ptr := unsafe.Pointer(&t)
							 | 
						||
| 
								 | 
							
									p.UnsafePool.Put(ptr)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// UnsafePool provides an incredibly
							 | 
						||
| 
								 | 
							
								// simple memory pool implementation
							 | 
						||
| 
								 | 
							
								// that stores ptrs to memory values,
							 | 
						||
| 
								 | 
							
								// and regularly flushes internal pool
							 | 
						||
| 
								 | 
							
								// structures according to DirtyFactor.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note it is NOT safe for concurrent
							 | 
						||
| 
								 | 
							
								// use, you must protect it yourself!
							 | 
						||
| 
								 | 
							
								type UnsafePool struct {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// DirtyFactor determines the max
							 | 
						||
| 
								 | 
							
									// number of $dirty count before
							 | 
						||
| 
								 | 
							
									// pool is garbage collected. Where:
							 | 
						||
| 
								 | 
							
									// $dirty = len(current) - len(victim)
							 | 
						||
| 
								 | 
							
									DirtyFactor int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									current []unsafe.Pointer
							 | 
						||
| 
								 | 
							
									victim  []unsafe.Pointer
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *UnsafePool) Get() unsafe.Pointer {
							 | 
						||
| 
								 | 
							
									// First try current list.
							 | 
						||
| 
								 | 
							
									if len(p.current) > 0 {
							 | 
						||
| 
								 | 
							
										ptr := p.current[len(p.current)-1]
							 | 
						||
| 
								 | 
							
										p.current = p.current[:len(p.current)-1]
							 | 
						||
| 
								 | 
							
										return ptr
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Fallback to victim.
							 | 
						||
| 
								 | 
							
									if len(p.victim) > 0 {
							 | 
						||
| 
								 | 
							
										ptr := p.victim[len(p.victim)-1]
							 | 
						||
| 
								 | 
							
										p.victim = p.victim[:len(p.victim)-1]
							 | 
						||
| 
								 | 
							
										return ptr
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *UnsafePool) Put(ptr unsafe.Pointer) {
							 | 
						||
| 
								 | 
							
									p.current = append(p.current, ptr)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Get dirty factor.
							 | 
						||
| 
								 | 
							
									df := p.DirtyFactor
							 | 
						||
| 
								 | 
							
									if df == 0 {
							 | 
						||
| 
								 | 
							
										df = DefaultDirtyFactor
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if len(p.current)-len(p.victim) > df {
							 | 
						||
| 
								 | 
							
										// Garbage collection!
							 | 
						||
| 
								 | 
							
										p.victim = p.current
							 | 
						||
| 
								 | 
							
										p.current = nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |