00001 /* file "referenced_item.h" */ 00002 00003 00004 /* 00005 Copyright (c) 1996, 1997 Stanford University 00006 00007 All rights reserved. 00008 00009 This software is provided under the terms described in 00010 the "suif_copyright.h" include file. 00011 */ 00012 00013 #include <common/suif_copyright.h> 00014 00015 #ifndef STY_REFERENCED_ITEM_H 00016 #define STY_REFERENCED_ITEM_H 00017 00018 #include "suifkernel/suifkernel_forwarders.h" 00019 00020 /* 00021 This is the definition of the referenced_item class, which is 00022 for internal use by sty, the first-level main library of the 00023 SUIF system. 00024 */ 00025 00026 00027 /* 00028 The idea of this class is that for various interfaces in sty, we 00029 want to pass back to the user a reference to something internal 00030 (reference not meaning necessarily a C++ reference, but the more 00031 general sense of the word reference). Essentially, a pointer is 00032 being returned that the user can then later pass to other 00033 methods of the interface. But some implementations of a 00034 particular interface may pass pointers to structures they keep 00035 anyway, while other implementations may build the internal 00036 structures on-the-fly when a reference to them is requested by 00037 the user. An example of this is a handle for an element in a 00038 tos, which in a linked-list implementation is a pointer to an 00039 item in the list while in an array implementation it's an 00040 auxiliary structure that is only constructed when such a handle 00041 is requested by the user. We want to be able to delete the 00042 specially constructed structure when the user is done with the 00043 reference to it. We handle this by passing a special handle 00044 class to the user where the handle contains only one field, the 00045 pointer. The only differences between the pointer itself and 00046 the handle are that the handle will tell the pointer when the 00047 handle is copied or de-allocated and if necessary deallocate it 00048 when the last reference is de-allocated. We implement this by 00049 having all such internal structures inherit from this pure 00050 virtual class, referenced_item. 00051 00052 Having a class wrapped around the pointer given to a user also 00053 gives the added benefit of making it somewhat harder to 00054 circumvent the separation of interface and implementation. 00055 Since pointer casts happen all over the place and are entirely 00056 necessary in C++ to move up the class heirarchy, it's tempting 00057 to simply cast a pointer a user is given to get access to the 00058 internals of what the user knows it points to. The wrapper 00059 class makes it hard enough to discourage such usage. 00060 00061 Note that it's important to have a single class for all things 00062 that the user is going to get a handle to so that 00063 behind-the-scenes one class can use the handle it gets from a 00064 component class to give to the user as a totally different kind 00065 of handle. The handle classes should have different types for 00066 better type checking. That means that some classes will 00067 actually have to be made dependent on the internals of the 00068 handle for another class (though only to the extent of knowing 00069 that the handle is just a wrapper for a referenced_item 00070 pointer). This is a small reduction in modularity, but it is 00071 necessary to get efficient implementations the way these 00072 interfaces are structured. 00073 */ 00074 //#include "sty_basics.h" 00075 00076 class referenced_item 00077 { 00078 private: 00079 // virtual void virtual_function_table_hack(void); 00080 00081 protected: 00082 referenced_item(void) { } 00083 00084 public: 00085 virtual ~referenced_item(void) { } 00086 00087 virtual void add_ref(void) = 0; 00088 virtual void remove_ref(void) = 0; 00089 virtual bool delete_me(void) = 0; 00090 }; 00091 00092 class ri_reference 00093 { 00094 private: 00095 // virtual void virtual_function_table_hack(void); 00096 00097 protected: 00098 referenced_item *_data; 00099 00100 void old_ref(referenced_item *old_data) 00101 { 00102 if (old_data != 0) 00103 { 00104 old_data->remove_ref(); 00105 if (old_data->delete_me()) 00106 delete old_data; 00107 } 00108 } 00109 00110 ri_reference(const ri_reference &) : _data(0) {}; 00111 ri_reference &operator=(const ri_reference &) { suif_assert(0); return *this; } 00112 00113 ri_reference(void) : _data(0) {} 00114 ri_reference(referenced_item *init_data) : _data(init_data) 00115 { 00116 if (init_data != 0) 00117 init_data->add_ref(); 00118 } 00119 virtual ~ri_reference(void) { old_ref(_data); } 00120 00121 public: 00122 /* no public constructors or destructors should exist here */ 00123 00124 bool is_null(void) const { return _data == 0; } 00125 00126 /* DANGER! The following allows access to the raw referenced_item 00127 * pointer. Avoid using this if at all possible. If it is used, 00128 * the user is responsible for seeing that add_ref() and 00129 * remove_ref() are called when appropriate on the resulting 00130 * pointer. */ 00131 referenced_item *raw_referenced_item(void) const { return _data; } 00132 void set_raw_referenced_item(referenced_item *new_data) 00133 { 00134 if (new_data != 0) 00135 new_data->add_ref(); 00136 old_ref(_data); 00137 _data = new_data; 00138 } 00139 }; 00140 00141 00142 #endif /* STY_REFERENCED_ITEM_H */