<commit_before>use std::mem::size_of;
use std::ptr;
use std::sync::Mutex;

use gc::arena;
use gc::Address;
use gc::swiper::Region;
use gc::swiper::LARGE_OBJECT_SIZE;
use mem;

pub struct LargeSpace {
    total: Region,
    ranges: Mutex<Ranges>,
}

impl LargeSpace {
    pub fn new(start: Address, end: Address) -> LargeSpace {
        LargeSpace {
            total: Region::new(start, end),
            ranges: Mutex::new(Ranges::new(start, end)),
        }
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        debug_assert!(size >= LARGE_OBJECT_SIZE);
        let size = mem::page_align(size_of::<LargeAlloc>() + size);

        let mut ranges = self.ranges.lock().unwrap();

        if let Some(range) = ranges.alloc(size) {
            arena::commit(range.start, range.size(), false).expect("couldn't commit large object.");
            ranges.append_large_alloc(range.start, range.size());
            range.start.to_ptr()

        } else {
            ptr::null()
        }
    }

    pub fn free(&self, ptr: Address, size: usize) {
        debug_assert!(size >= LARGE_OBJECT_SIZE);
        debug_assert!(mem::is_page_aligned(ptr.to_usize()));
        let size = mem::page_align(size_of::<LargeAlloc>() + size);

        let mut ranges = self.ranges.lock().unwrap();
        debug_assert!(!ranges.contains(ptr));
        ranges.free(ptr, size);
        ranges.merge();
    }

    pub fn contains(&self, addr: Address) -> bool {
        self.total.contains(addr)
    }
}

struct LargeAlloc {
    prev: Address,
    next: Address,
    size: usize,
}

struct Ranges {
    elements: Vec<Range>,
    head: Address,
    tail: Address,
}

impl Ranges {
    fn new(start: Address, end: Address) -> Ranges {
        Ranges {
            elements: vec![Range::new(start, end)],
            head: Address::null(),
            tail: Address::null(),
        }
    }

    fn alloc(&mut self, size: usize) -> Option<Range> {
        debug_assert!(mem::is_page_aligned(size));
        let len = self.elements.len();

        for i in 0..len {
            if self.elements[i].size() >= size {
                let range = self.elements[i];
                let alloc = Range::new(range.start, range.start.offset(size));

                if range.size() == size {
                    self.elements.remove(i);
                } else {<commit_msg>swiper: rename Ranges to LargeSpaceProtected<commit_after>use std::mem::size_of;
use std::ptr;
use std::sync::Mutex;

use gc::arena;
use gc::Address;
use gc::swiper::Region;
use gc::swiper::LARGE_OBJECT_SIZE;
use mem;

pub struct LargeSpace {
    total: Region,
    space: Mutex<LargeSpaceProtected>,
}

impl LargeSpace {
    pub fn new(start: Address, end: Address) -> LargeSpace {
        LargeSpace {
            total: Region::new(start, end),
            space: Mutex::new(LargeSpaceProtected::new(start, end)),
        }
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        debug_assert!(size >= LARGE_OBJECT_SIZE);
        let size = mem::page_align(size_of::<LargeAlloc>() + size);

        let mut space = self.space.lock().unwrap();

        if let Some(range) = space.alloc(size) {
            arena::commit(range.start, range.size(), false).expect("couldn't commit large object.");
            space.append_large_alloc(range.start, range.size());
            range.start.to_ptr()

        } else {
            ptr::null()
        }
    }

    pub fn free(&self, ptr: Address, size: usize) {
        debug_assert!(size >= LARGE_OBJECT_SIZE);
        debug_assert!(mem::is_page_aligned(ptr.to_usize()));
        let size = mem::page_align(size_of::<LargeAlloc>() + size);

        let mut space = self.space.lock().unwrap();
        debug_assert!(!space.contains(ptr));
        space.free(ptr, size);
        space.merge();
    }

    pub fn contains(&self, addr: Address) -> bool {
        self.total.contains(addr)
    }
}

struct LargeAlloc {
    prev: Address,
    next: Address,
    size: usize,
}

struct LargeSpaceProtected {
    elements: Vec<Range>,
    head: Address,
    tail: Address,
}

impl LargeSpaceProtected {
    fn new(start: Address, end: Address) -> LargeSpaceProtected {
        LargeSpaceProtected {
            elements: vec![Range::new(start, end)],
            head: Address::null(),
            tail: Address::null(),
        }
    }

    fn alloc(&mut self, size: usize) -> Option<Range> {
        debug_assert!(mem::is_page_aligned(size));
        let len = self.elements.len();

        for i in 0..len {
            if self.elements[i].size() >= size {
                let range = self.elements[i];
                let alloc = Range::new(range.start, range.start.offset(size));

                if range.size() == size {
                    self.elements.remove(i);
                } else {
{'fraction_non_alphanumeric': 0.14670283806343906, 'fraction_numerical': 0.0008347245409015025, 'mean_word_length': 2.3354210160055673, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4974451', 'n_tokens_mistral': 1495, 'n_tokens_neox': 1482, 'n_words': 326}