#include <kernel/kernel.h> #include <phantasmal/lpc_names.h> private mapping segments; private string* owners; private int segments_full; private int highest_segment; /* Prototypes */ void upgraded(varargs int clone); static void create(varargs int clone) { if(clone) { error("Can't clone objnumd!"); } segments = ([ ]); segments_full = -1; highest_segment = -1; upgraded(); } void upgraded(varargs int clone) { if(SYSTEM() || COMMON()) owners = ({ MAPD, EXITD, MOBILED }); } void destructed(varargs int clone) { if(SYSTEM()) { } } private int owner_for_program(string program_name) { int owner; for(owner = 0; owner < sizeof(owners); owner++) { if(program_name == owners[owner]) return owner; } return -1; } string get_segment_owner(int segment) { if(!SYSTEM() && !COMMON()) return nil; if(segments[segment]) { return owners[segments[segment][0]]; } else return nil; } int get_highest_segment(void) { if(!SYSTEM() && !COMMON()) return -1; return highest_segment; } private void set_segment_owner(int segment, int owner) { if(segment < 0) error("Can't allocate negative segment in set_segment_owner!"); if(segments[segment]) { segments[segment][0] = owner; return; } /* This location defines segment structure... */ segments[segment] = ({ owner, ({ }) }); if(segments_full == segment - 1) { while(segments[segments_full + 1]) segments_full++; } if(segment > highest_segment) highest_segment = segment; } int allocate_new_segment(void) { int owner; int seg; owner = owner_for_program(previous_program()); if(owner == -1) error("Unknown owner " + previous_program() + " calling allocate_new_segment!"); seg = segments_full + 1; if(get_segment_owner(seg)) { error("Internal error -- attempting to reassign segment!"); } set_segment_owner(seg, owner); return seg; } private void unallocate_segment(int segment) { error("Should not use?"); if(segments_full >= segment) { segments_full = segment - 1; } if(segment == highest_segment) { error("Haven't implemented recalculating highest segment!"); } segments[segment] = nil; } /* Note: doing an allocate_in_segment with a valid tracking number and nil as the object is a quite acceptable way to allocate or pre-grow a segment */ void allocate_in_segment(int segment, int tr_num, object obj) { int offs; mixed* seg; int owner; if(tr_num < 0) error("Negative tracking number in allocate_in_segment!"); if(tr_num / 100 != segment) error("Tracking number not in segment in allocate_in_segment!"); owner = owner_for_program(previous_program()); if(owner == -1) error("Unknown owner " + previous_program() + " calling allocate_in_segment!"); offs = tr_num % 100; seg = segments[segment]; if(!seg) { /* Allocate a new segment for caller */ set_segment_owner(segment, owner); seg = segments[segment]; if(!seg) error("Cannot allocate segment -- why?"); } if(seg[0] != owner) error(owners[owner] + " can't allocate object " + tr_num + " in segment " + segment + "!\n" + "That segment is owned by " + owners[seg[0]] + "!"); if(sizeof(segments[segment][1]) <= offs) { seg[1] += allocate(offs - sizeof(seg[1]) + 1); } if(seg[1][offs]) error("Reassigning used number #" + tr_num + " in allocate_in_segment!"); seg[1][offs] = obj; } /* Note: because a destructed object's references will all become nil automatically, doing a remove_from_segment is unnecessary if the object has already been destructed */ void remove_from_segment(int segment, int tr_num) { mixed* seg; int offs; seg = segments[segment]; if(!seg) error("Can't remove from unallocated segment!"); if(tr_num / 100 != segment) error("Can't remove tr_num from different segment!"); offs = tr_num % 100; if(sizeof(seg[1]) <= offs || !seg[1][offs]) error("Object not in segment in remove_from_segment!"); seg[1][offs] = nil; } /* A segment owner calls this function to retrieve an object from its own segment. */ object get_object(int tr_num) { int segment, offs; int owner; object ret; if(tr_num < 0) error("Tracking numbers must be >= 0!"); segment = tr_num / 100; offs = tr_num % 100; owner = segments[segment] ? segments[segment][0] : -1; if(owner == -1 || owners[owner] != previous_program()) { return nil; } if(sizeof(segments[segment][1]) <= offs) { return nil; } ret = segments[segment][1][offs]; return ret; } /* Attempts to allocate a new tracking number in the given segment. If the segment is full, it returns -1. */ int new_in_segment(int segment, object obj) { mixed* seg; int ctr; seg = segments[segment]; if(!seg) { set_segment_owner(segment, owner_for_program(previous_program())); seg = segments[segment]; } if(owners[seg[0]] != previous_program()) error("Can't allocate in segment you don't own!"); for(ctr = 0; ctr < sizeof(seg[1]); ctr++) { if(!seg[1][ctr]) { seg[1][ctr] = obj; return segment * 100 + ctr; } } if(sizeof(seg[1]) < 100) { int offs; offs = sizeof(seg[1]); seg[1] += allocate(1); seg[1][offs] = obj; return segment * 100 + offs; } return -1; } /* Returns a list of object numbers in an owned segment. Caller must be the segment owner and the segment must be allocated. */ int* objects_in_segment(int segment) { int* objs; int ctr, tr_num; mixed* seg; seg = segments[segment]; if(!seg || previous_program() != owners[seg[0]]) error("Can't get listing of segment " + segment + " that you don't own!"); objs = ({ }); for(ctr = 0, tr_num = segment*100; ctr < sizeof(seg[1]); ctr++, tr_num++) { if(seg[1][ctr]) { objs += ({ tr_num }); } } return objs; }