Created
December 13, 2013 13:57
-
-
Save ezyang/7944606 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pub fn alloc_mega_group(mblocks: nat) -> ~Block { | |
| let n = MBLOCK_GROUP_BLOCKS(mblocks); | |
| enum SearchResult<'a> { | |
| PerfectMatch(~Block), | |
| BestMatch(&'a mut BlockData, &'a mut BlockMeta), | |
| NoMatch | |
| } | |
| // tail-recursive style makes the borrow-checker *a lot* | |
| // happier, since some of the aliasing effects that occur when | |
| // local mutable variables are reused go away (fresh lexical | |
| // scope, fresh lifetime, it's great) | |
| fn go<'a>(n: uint, | |
| prev_link: &'a mut Option<~Block>, | |
| best: Option<(&'a mut BlockData, &'a mut BlockMeta)>) | |
| -> SearchResult<'a> { | |
| match prev_link { | |
| &None => match best { | |
| None => NoMatch, | |
| Some((data, meta)) => BestMatch(data, meta) | |
| }, | |
| // NB: need to match it out, so we don't take out a | |
| // reference on prev_link that will interfere with the | |
| // take() | |
| &Some(~Block {meta: BlockMeta {blocks, ..}, ..}) if blocks as uint == n => { | |
| let mut bd = prev_link.take_unwrap(); | |
| *prev_link = bd.link.p.take(); | |
| PerfectMatch(bd) | |
| }, | |
| &Some(ref mut bd) => { | |
| if bd.meta.blocks as uint > n && match best { | |
| None => true, | |
| Some((_, ref best_meta)) => bd.meta.blocks < best_meta.blocks | |
| } { | |
| go(n, &mut bd.link.p, Some((&mut bd.data, &mut bd.meta))) | |
| } else { | |
| go(n, &mut bd.link.p, best) | |
| } | |
| } | |
| } | |
| } | |
| // NB: global_ref can be used to mutate global state | |
| let mut global_ref = unsafe { &mut free_mblock_list.p }; | |
| let mut bd: ~Block = match go(n, global_ref, None) { | |
| // We found a perfect match and removed it from the list | |
| PerfectMatch(p) => return p, | |
| // Take our chunk off the end of the best match | |
| BestMatch(ref data, ref mut meta) => { | |
| let best_mblocks = BLOCKS_TO_MBLOCKS(meta.blocks as uint); | |
| // bd = FIRST_BDESCR((StgWord8*)MBLOCK_ROUND_DOWN(best) +· | |
| // (best_mblocks-mblocks)*MBLOCK_SIZE); | |
| meta.blocks = MBLOCK_GROUP_BLOCKS(best_mblocks - mblocks) as u32; | |
| fail!("initMBlock(MBLOCK_ROUND_DOWN(bd));") | |
| }, | |
| // Nothing in the free list was big enough, so allocate | |
| NoMatch => { | |
| let mut mblock = MBlock::new(mblocks); | |
| fail!("bd = FIRST_BDESCR(mblock);"); | |
| }, | |
| }; | |
| bd.meta.blocks = MBLOCK_GROUP_BLOCKS(mblocks) as u32; | |
| return bd | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment