/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef INCLUDE_ECXX_PLATFORM_SPECIFIC_PROGMEM_FUNCTOR_H
#error "this file cannot be included directly"
#endif
#undef INCLUDE_ECXX_PLATFORM_SPECIFIC_PROGMEM_FUNCTOR_H


#ifndef ECXX_PLATFORM_AVR_COMMON_PROGMEM_FUNCTOR_H
#define ECXX_PLATFORM_AVR_COMMON_PROGMEM_FUNCTOR_H


namespace eCxx {


//
// Platform-specific's program-memory functors
//

// Inform that the platform-specific's program-memory functors have been defined here
#define ECXX_PROGMEM_FUNCTOR_DEFINED

// Read a byte
struct PGMReadByte {
    inline uint8_t operator()(_PGMVoidPointer ptr) const noexcept
    { return pgm_read_byte_near(ptr); }

#ifdef __AVR_HAVE_ELPM__
    inline uint8_t operator()(_PGMVoidPointerFar ptr) const noexcept
    { return pgm_read_byte_far(ptr); }
#endif
};

// Read a word
struct PGMReadWord {
    inline uint16_t operator()(_PGMVoidPointer ptr) const noexcept
    { return pgm_read_word_near(ptr); }

#ifdef __AVR_HAVE_ELPM__
    inline uint16_t operator()(_PGMVoidPointerFar ptr) const noexcept
    { return pgm_read_word_far(ptr); }
#endif
};

// Read a dword
struct PGMReadDWord {
    inline uint32_t operator()(_PGMVoidPointer ptr) const noexcept
    { return pgm_read_dword_near(ptr); }

#ifdef __AVR_HAVE_ELPM__
    inline uint32_t operator()(_PGMVoidPointerFar ptr) const noexcept
    { return pgm_read_dword_far(ptr); }
#endif
};

// Memory copy
struct PGMMemCpy {
    inline void operator()(void* dst, _PGMVoidPointer src, size_t len) const noexcept
    { ::memcpy_P(dst, src, len); }

#ifdef __AVR_HAVE_ELPM__
    inline void operator()(void* dst, _PGMVoidPointerFar src, size_t len) const noexcept
    { ::memcpy_PF(dst, src, len); }
#endif
};

// String copy
struct PGMStrNCpy {
    inline void operator()(char* dst, _PGMCharPointer src, size_t max) const noexcept
    { ::strncpy_P(dst, src, max); }

#ifdef __AVR_HAVE_ELPM__
    inline void operator()(char* dst, _PGMCharPointerFar src, size_t max) const noexcept
    { ::strncpy_PF(dst, src, max); }
#endif
};

// String compare
struct PGMStrNCmp {
    inline int operator()(const char* ptr1, _PGMCharPointer ptr2, size_t max) const noexcept
    { return ::strncmp_P(ptr1, ptr2, max); }

#ifdef __AVR_HAVE_ELPM__
    inline int operator()(const char* ptr1, _PGMCharPointerFar ptr2, size_t max) const noexcept
    { return ::strncmp_PF(ptr1, ptr2, max); }
#endif
};

// String length
struct PGMStrNLen {
    inline size_t operator()(_PGMCharPointer ptr, size_t max) const noexcept
    { return ::strnlen_P(ptr, max); }

#ifdef __AVR_HAVE_ELPM__
    inline size_t operator()(_PGMCharPointerFar ptr, size_t max) const noexcept
    { return ::strnlen_PF(ptr, max); }
#endif
};


} // namespace eCxx


#endif
