### The IRanges class is a simple container for storing a vector of integer
### A NormalIRanges object is an IRanges object where the ranges are:
###   (a) not empty (i.e. they have a non-null width);
###   (d) not even adjacent (i.e. there must be a non empty gap between 2
### If 'x' is an IRanges object of length >= 2, then 'x' is normal iff:
### If length(x) == 1, then 'x' is normal iff width(x)[1] >= 1.
### If length(x) == 0, then 'x' is normal.
### Efficient "isNormal" method for IRanges objects.
### The "isEmpty" default method for Ranges objects would work just fine on a
### NormalIRanges object but we can take advantage of the normality to make
### Note: defined for NormalIRanges objects only.
### For an ordinary IRanges object 'x', it's not clear what the semantic
### should be. In particular, should empty ranges be ignored or not? If not
### then we could end up with 'min(x)' > 'max(x)' (e.g. when 'x' is made of 1
### empty range) which is not nice. Another (and more pragmatic) reason for
### not defining these methods for IRanges objects is that I don't need them
### Both 'start(x)' and 'width(x)' must be unnamed integer vectors of equal
### length (eventually 0) with no NAs and such that 'all(width >= 0)' is TRUE.
### 'names(x)' must be NULL or an unnamed character vector of the same length
### Note that we use 'min(width(x)) < 0L' in .valid.IRanges.width() because
### the 'min(x) < val' test is generally faster and more memory efficent than
### the 'any(x < val)' test, especially when 'x' is a big vector (the speedup
### is around 10x or more when 'length(x)' is >= 100000). The 2 tests are
### equivalent when 'length(x)' != 0 and 'length(val)' == 1.
"'start(x)' must be an unnamed integer vector with no NAs"
"'start(x)' and 'width(x)' must have the same length"
"'width(x)' must be an unnamed integer vector with no NAs"
"'widths(x)' cannot contain negative values"
## Even if 'start(x)' and 'width(x)' are valid, 'end(x)' (which is
## obtained by doing 'start(x) + width(x) - 1L') could contain NAs
### Any Ranges object can be turned into an IRanges instance.
### Helper function (not exported) used by the "coerce" methods defined in
### IRanges-utils.R. Believe it or not but the implicit "coerce" methods do
### NOT check that they return a valid object!
## Make a "hard copy" of the slots. No need to check anything!
### The returned IRanges instance is guaranteed to be normal.
### Low-level (i.e. non-exported and unsafe) replacement functions for
### The choice was made to implement a "resizing" semantic:
###   (1) changing the start preserves the end (so it changes the width)
###   (2) changing the end preserves the start (so it changes the width)
###   (3) changing the width preserves the start (so it changes the end)
### IMPORTANT: They do NOT check their arguments ('x' and 'value'). In
### particular they do not check that 'value' is of the expected type (integer
### for "unsafe.start<-", "unsafe.width<-", "unsafe.end<-", and character for
### "unsafe.names<-"). Also they don't check that the resulting IRanges object
## Use 'x@start[]' instead of just 'x@start' so the right value is recycled
## Use 'x@width[]' instead of just 'x@width' so the right value is recycled
### 'value' is NOT recycled so we stay close to what the standard R "names<-"
### Exported (and safe) replacement methods.
### See the unsafe replacement functions for IRanges objects above for the
### Note that we don't call validObject(x) after 'x' has been modified because
### we don't need to revalidate the entire object: validating the bits that
### have been touched is enough (and faster). However, because of this, when
### defining a new class that contains the IRanges class, if objects of
### the new class must satisfy additional constraints, then some of the
### replacement methods below need to be overridden for this new class.
### This is a convenience method for combining multiple modifications in one
### It must verify 2 important properties:
###   (1) update(x) must be identical to x (doesn't touch x at all)
###   (2) update(x, start=start(x), width=width(x), names=names(x))
###       must be identical to x too (but this time it updates x with its own
### FIXME: need some way of specifying the extent of validity
### checking, like giving the class up to which the object is
### The "c" method for IRanges objects is implemented to behave like an
### endomorphism i.e. to return an object of the same class as 'x'. In
### particular 'c(x)' now returns 'x' and not 'as(x, "IRanges")'.
### It's easy to implement specific "c" methods for IRanges subclasses.
### Typically they just need to do something like:
###     ans <- callNextMethod(x, ..., recursive=FALSE)
### and to take care of the additional slots (aka the subclass-specific
### slots). If there aren't any additional slots (e.g. NormalIRanges), or
### if the additional slots don't need to be modified (e.g. the "subject"
### slot of the Views subclass), then no need to implement a specific method
### In the case of NormalIRanges objects, 'c(x1, x2)' will fail if the result
### is not normal, but 'c(as(x1, "IRanges"), x2)' or 'c(IRanges(), x1, x2)'
### would work. Note that, in general, 'c(IRanges(), x)' is not the same as
### 'c(x, IRanges())' (the former is equivalent to 'as(x, IRanges)' and the
### Also note that the user needs to be carefull when passing named arguments
### to c() (there is no good reason to do this in the first place) because of
###  (1) If all the arguments are named (e.g. 'c(a=x1, b=x2)') then the first
###      argument must be an IRanges *instance* otherwise dispatch will fail.
###      It's not clear why dispatch works when 'x1' is an IRanges instance
###      because, in that case, formal argument 'x' is missing. It's even
###      less clear why it fails when 'x1' is an IRanges object without being
###      an IRanges instance. For example:
###        ## dispatch fails (the default "c" method is selected)
###  (2) When named and unnamed arguments are mixed and no named argument has
###      name 'x' (e.g. 'c(a=x1, x2)'), then, following the standard rules of
###      argument matching in R, one would expect that the first unnamed
###      argument will match formal argument 'x'. This is more or less what
###          all arguments in '...' must be logical objects (or NULLs)