There are two ways to go about this and you will need to decide which way you want to go.
1) translate all the information at compile time which will generate AVR bit set/clr instructions.
This yields the smallest fastest code but it requires that all the information pin # and data value
be constant and known at compile time.
This means that the sketch cannot define the pins in a constructor and configuration must
be done using some other means. For a library it usually means that it must have its own
config file for the pin information.
2) translate the information runtime once and then use it directly instead of calling digitalWrite()/digitalRead().
This can be done in a portable manor (will work on AVR, pic32, and ARM), and while not as fast
as bit set/clr instructions, it will be much faster than digitalWrite()/digitalRead() particularly on AVR
It comes with a caveat that you must mask interrupts when
altering the port register to avoid port corruption.
To do this you use these functions:
port_addr = portOutputRegister(digitalPinToPort(pin#));
port_mask = digitalPinToBitMask(pin#);
Then you can twiddle the bits directly:
*port_addr |= port_mask; // set bit
*port_addr &= ~port_mask; // set bit
But remember, interrupts must be masked when you do this to avoid port corruption.
To get portability the data type for port_addr and port_mask will be different
for different processors.
I haven't looked at the ARM registers but for AVR and pic32 you can use this:
#if defined (__AVR__)
typedef uint8_t fio_bit;
typedef volatile uint8_t *fio_register;
typedef uint32_t fio_bit;
typedef volatile uint32_t *fio_register;
Then define port_addr as a fio_register and port_bit as a fio_bit
If you want to have smarter code for the pic32, (which is not portable to other MPUs)
the pic32 parts have bit set/clr registers
that could be use that work even better than the AVR bit set/clr instructions since
for this mode of operation bit set/clr instructions can't be used
and the pic bit set/clr registers can atomically set/clr bits and
don't require that interrupts be masked like the AVR.