Range.h   [plain text]


/*
 * Copyright (c) 2011 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */
/*
    Range.h
    Contiguous Address Range
    Copyright (c) 2004-2011 Apple Inc. All rights reserved.
 */

#pragma once
#ifndef __AUTO_RANGE__
#define __AUTO_RANGE__


#include "Definitions.h"


namespace Auto {

    //----- Range -----//

    //
    // Manage an area of memory
    //

    class Range {

      private:

        void *_address;                                     // start of range
        void *_end;                                         // end of the range (one byte beyond last usable space)
      
      public:
      
        //
        // Constructors
        //
        Range()                             : _address(NULL),    _end(NULL) {}
        Range(void *address)                : _address(address), _end(address) {}
        Range(void *address, void *end)     : _address(address), _end(end) {}
        Range(void *address, usword_t size) : _address(address), _end(displace(address, size)) {}
        
        
        //
        // Accessors
        //
        inline       Range&   range()                                       { return *this; }
        inline       void     *address()                              const { return _address; }
        inline       void     *end()                                  const { return _end; }
        inline const usword_t size()                                  const { return (uintptr_t)_end - (uintptr_t)_address; }
        inline       void     set_address(void *address)                    { _address = address; }
        inline       void     set_end(void *end)                            { _end = end; }
        inline       void     set_size(usword_t size)                       { _end = displace(_address, size); }
        inline       void     set_range(void *address, void *end)           { _address = address; _end = end; }
        inline       void     set_range(void *address, usword_t size)       { _address = address; _end = displace(address, size); }
        inline       void     set_range(Range range)                        { _address = range.address(); _end = range.end(); }
        inline       void     adjust_address(intptr_t delta)                { _address = displace(_address, delta); }
        inline       void     adjust_end(intptr_t delta)                    { _end = displace(_end, delta); }
        inline       void     adjust(intptr_t delta)                        { _address = displace(_address, delta), _end = displace(_end, delta); }
        
        
        //
        // is_empty
        //
        // Returns true if the range is empty.
        //
        inline bool is_empty() { return _address == _end; }

        
        //
        // in_range
        //
        // Returns true if the specified address is in range.
        // This form reduces the number of branches.  Works well with invariant lo and hi.
        //
        static inline const bool in_range(void *lo, void *hi, void *address) {
            uintptr_t lo_as_int = (uintptr_t)lo;
            uintptr_t hi_as_int = (uintptr_t)hi;
            uintptr_t diff = hi_as_int - lo_as_int;
            uintptr_t address_as_int = (uintptr_t)address;
            return (address_as_int - lo_as_int) < diff;
        }
        inline const bool in_range(void *address) const { return in_range(_address, _end, address); }
        
        
        //
        // operator ==
        //
        // Used to locate entry in list or hash table (use is_range for exaxt match.)
        inline const bool operator==(const Range *range)  const { return _address == range->_address; }
        inline const bool operator==(const Range &range)  const { return _address == range._address; }
        
        //
        // is_range
        //
        // Return true if the ranges are equivalent.
        //
        inline const bool is_range(const Range& range) const { return _address == range._address && _end == range._end; }
        
        
        //
        // clear
        //
        // Initialize the range to zero.
        //
        inline void clear() { bzero(address(), size()); }
        
        //
        // uncommit
        //
        // Tell the operating system the contents of the pages can be purged.
        //
        inline void uncommit() { uncommit_memory(address(), size()); }

        //
        // commit
        //
        // Tell the operating system the pages in this range are about to be reused.
        //
        inline void commit() { commit_memory(address(), size()); }

        //
        // expand_range
        //
        // Expand the bounds with the specified range.
        //
        inline void expand_range(void *address) {
            if (_address > address) _address = address;
            if (_end < address) _end = address;
        }
        inline void expand_range(Range& range) {
            expand_range(range.address());
            expand_range(range.end());
        }
                
        
        //
        // relative_address
        //
        // Converts an absolute address to an address relative to this address.
        //
        inline void *relative_address(void *address) const { return (void *)((uintptr_t)address - (uintptr_t)_address); }

        
        //
        // absolute_address
        //
        // Converts an address relative to this address to an absolute address.
        //
        inline void *absolute_address(void *address) const { return (void *)((uintptr_t)address + (uintptr_t)_address); }
        
        
    };
        
};

#endif // __AUTO_RANGE__